java8 Stream使用總結 java8 函數接口 java8 Optional使用總結 Java 8 時間日期使用 java8 lambda表達式

【前言】 java8新特性html

java8 函數接口

java8 Optional使用總結

Java 8 時間日期使用

java8 lambda表達式

 

一、流的介紹

Java8 中的 Stream 是對集合(Collection)對象功能的加強,它專一於對集合對象進行各類很是便利、高效的聚合操做(aggregate operation),或者大批量數據操做 (bulk data operation)。它提供串行和並行兩種模式進行匯聚操做,併發模式可以充分利用多核處理器的優點,使用 fork/join 並行方式來拆分任務和加速處理過程。Stream API 藉助於一樣新出現的 Lambda 表達式,極大的提升編程效率和程序可讀性。
而在Java 的集合 API 中,僅僅有極少許的輔助型方法,更多的時候是程序員須要用 Iterator 來遍歷集合,完成相關的聚合應用邏輯。
所謂聚合操做就相似SQL語句同樣的操做, 好比filter, map, reduce, find, match, sorted等。java

二、流的特色

Stream 不是集合元素,它不是數據結構並不保存數據,它是有關算法和計算的,它更像一個高級版本的 Iterator,用戶只要給出須要對其包含的元素執行什麼操做,Stream 會隱式地在內部進行遍歷,作出相應的數據轉換,好比 「過濾掉長度大於 10 的字符串」。而原始版本的 Iterator,用戶只能顯式地一個一個遍歷元素並對其執行某些操做。
Stream 如同一個迭代器(Iterator),單向,不可往復,數據只能遍歷一次,遍歷過一次後即用盡了。和迭代器不一樣的是,Stream 能夠並行化操做,迭代器只能命令式地、串行化操做,Stream 的並行操做依賴於 Java7 中的 Fork/Join 框架(JSR166y)來拆分任務和加速處理過程。git

三、流的操做類型

中間操做(intermediate )
一個流能夠後面跟隨零個或多個 intermediate 操做。其目的是打開流,作出某種程度的數據映射/過濾,而後返回一個新的流,交給下一個操做使用。這類操做都是惰性化的(lazy),僅僅調用到這類方法,並無真正開始流的遍歷。
對應方法有map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 skip、 parallel、 sequential、 unordered等

終止操做(terminal )
一個流只能有一個 terminal 操做,當這個操做執行後,流就被使用盡了,沒法再被操做,這是流的最後一個操做。
Terminal 操做的執行,纔會真正開始流的遍歷,而且會生成一個結果或者一個錯誤。
對應方法有forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、iterator

短路操做(short-circuiting)
對於一個 intermediate 操做,若是它接受的是一個無限大(infinite/unbounded)的 Stream,但返回一個有限的新 Stream。
對於一個 terminal 操做,若是它接受的是一個無限大的 Stream,但能在有限的時間計算出結果。
對應方法有anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit程序員

四、流的生成

流的來源能夠是集合,數組,I/O channel, 產生器generator 等。
基本數值型,目前有三種對應的包裝類型 Stream:IntStream、LongStream、DoubleStream。github

示例以下:算法

        /*************流的來源*************/
        // 一、of方法
        //      of(T... values):返回含有多個T元素的Stream
        //      of(T t):返回含有一個T元素的Stream
        Stream<String> single = Stream.of("a");
        Stream<String> multiple = Stream.of("a", "b", "c");

        // 二、generator方法,返回一個無限長度的Stream,其元素由Supplier接口的提供。
        Stream<String> generate = Stream.generate(() -> "a");
        Stream<Double> generateA = Stream.generate(new Supplier<Double>() {
            @Override
            public Double get() {
                return java.lang.Math.random();
            }
        });
        //  lambda寫法
        Stream<Double> generateB = Stream.generate(()-> java.lang.Math.random());
        Stream<Double> generateC = Stream.generate(java.lang.Math::random);

        // 三、iterate方法,返回的也是一個無限長度的Stream,與generate方法不一樣的是,其是經過函數f迭代對給指定的元素種子而產生無限連續有序Stream,其中包含的元素能夠認爲是:seed,f(seed),f(f(seed))無限循環
        Stream<Integer> iterate = Stream.iterate(1, item -> item + 2);
        // 無限流處理
        iterate.limit(10).forEach(System.out::println);

        // 四、empty方法返回一個空的順序Stream,該Stream裏面不包含元素項。
        Stream<Object> empty = Stream.empty();

        // 五、Collection接口和數組的默認方法
        String chars[] = new String[]{"a", "b", "c"};
        Arrays.stream(chars).forEach(System.out::println);

        List list = Arrays.asList(chars);
        list.stream().forEach(System.out::println);

五、流的相關使用

當你熟悉使用Lambda表達式時,就能夠很方便的進行流相關的操做了,提升代碼的編寫效率和程序的可讀性。編程

     /*************流的操做*************/
        //concat 將兩個Stream鏈接在一塊兒,合成一個Stream。若兩個輸入的Stream都時排序的,則新Stream也是排序的;若輸入的Stream中任何一個是並行的,則新的Stream也是並行的;若關閉新的Stream時,原兩個輸入的Stream都將執行關閉處理。
        Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5))
                .forEach(integer -> System.out.print(integer + "  "));

        //distinct 去除掉原Stream中重複的元素,生成的新Stream中沒有沒有重複的元素。
        Stream.of(1,1,3,4,3).distinct().forEach(System.out::println);

        //filter 對原Stream按照指定條件過濾,過濾出知足條件的元素。
        Stream.of(1,1,3,4,3).filter(x -> x > 2).forEach(System.out::println);

        //map方法將對於Stream中包含的元素使用給定的轉換函數進行轉換操做,新生成的Stream只包含轉換生成的元素。
        //爲了提升處理效率,官方已封裝好了,三種變形:mapToDouble,mapToInt,mapToLong,將原Stream中的數據類型,轉換爲double,int或者long類型。
        Stream.of("a", "b", "c")
                .map(item -> item.toUpperCase()) // .map(String::toUpperCase)
                .forEach(System.out::println);

        // flatMap方法與map方法相似,都是將原Stream中的每個元素經過轉換函數轉換,
        // 不一樣的是,該換轉函數的對象是一個Stream,也不會再建立一個新的Stream,而是將原Stream的元素取代爲轉換的Stream。
        List<User> users = UserUtil.getUsers(6);
        users.stream()
                .flatMap(s -> s.getInterests().stream())
                .forEach(System.out::println);

        Stream.of("a", "b", "c").flatMap(s -> Stream.of(s.toUpperCase()));

        //peek 生成一個包含原Stream的全部元素的新Stream,同時會提供一個消費函數(Consumer實例)
        Stream.of("a", "b", "c")
                //優先執行
                .peek(s -> System.out.println("peek:" + s))
                .forEach(System.out::println);

        //skip 將過濾掉原Stream中的前N個元素,返回剩下的元素所組成的新Stream。
        // 若是原Stream的元素個數大於N,將返回原Stream的後的元素所組成的新Stream;
        // 若是原Stream的元素個數小於或等於N,將返回一個空Stream。
        Stream.of("a", "b", "c").skip(2)
                .forEach(System.out::println);

        // sorted方法將對原Stream進行排序,返回一個有序列的新Stream。sorterd有兩種變體sorted(),sorted(Comparator),
        // 前者將默認使用Object.equals(Object)進行排序,然後者接受一個自定義排序規則函數(Comparator),可自定義進行排序。
        Stream.of(5, 6, 3, 9, 1)
                .sorted()
                .forEach(System.out::println);

        System.out.println("+++++++++++++++++++++++++++++++");
        Stream.of(5, 6, 3, 9, 1)
                .sorted(new Comparator<Integer>() {
                    @Override
                    public int compare(Integer o1, Integer o2) {
                        //asc
                        return o1 - o2;
                    }
                })
                .forEach(System.out::println);

        Stream.of(5, 6, 3, 9, 1)
                //desc
                .sorted(((o1, o2) -> o2 - o1))
                .forEach(System.out::println);
        System.out.println("+++++++++++++++++++++++++++++++");


        // count 將返回Stream中元素的個數。
        long count = Stream.of(1, 2, 3, 4, 5).count();
        System.out.println("count:" + count);

        // forEach 用於遍歷Stream中的所元素,避免了使用for循環,讓代碼更簡潔,邏輯更清晰。
        Stream.of("a", "b", "c").forEach(System.out::println);

        // forEachOrdered 與forEach相似,都是遍歷Stream中的全部元素,
        // 不一樣的是,若是該Stream預先設定了順序,會按照預先設定的順序執行(Stream是無序的),默認爲元素插入的順序。
        Stream.of(5,2,1,4,3)
                .forEachOrdered(integer ->
                    System.out.println("integer:" + integer)
                );

        // max 根據指定的Comparator,返回一個Optional,該Optional中的value值就是Stream中最大的元素。
        Optional<Integer> max = Stream.of(5, 2, 2, 3, 4, 8)
                .max((o1, o2) -> o2 - o1);
//        Optional<Integer> max3 = Stream.of(1, 2, 3, 4, 5)
//                .max(Comparator.comparingInt(x -> x));
        Optional<Integer> max3 = Stream.of(1, 2, 3, 4, 5)
                .max((o1, o2) -> o1 - o2);
        int max2 = Stream.of(1, 2, 3, 4, 5)
                .mapToInt(x -> x).max().getAsInt();
        System.out.println("max = " + max.get() + "  max2 = " + max2 + "  max3 = " + max3.orElse(-1));

        UserUtil.getUsers(6).stream()
                .sorted(Comparator.comparing(User::getName).thenComparing(User::getId))
                .forEach(u -> System.out.println(u.getName()));

        // min 根據指定的Comparator,返回一個Optional,該Optional中的value值就是Stream中最小的元素。
        Optional<Integer> min = Stream.of(1, 2, 3, 4, 5)
                .min((o1, o2) -> o1 - o2);
        System.out.println("min:" + min.get());

        System.out.println("*********************reduce********************");
        // reduce
        //  一、reduce((sum, item) -> { ... }); //返回Optional,由於可能存在爲空的狀況,
        //  二、reduce(0, (sum, item) -> { ... }); /返回對應類型,不存在爲空的狀況
        //無初始值,第一個參數爲stream的第一個元素,第二個參數爲stream的第二個元素,計算的結果賦值給下一輪計算的sum
        Optional<Integer> optional = Stream.of(1, 2, 3, 4, 5).reduce((sum, item) -> {
            System.out.println("sum before:" + sum);
            System.out.println("item:" + item);
            sum = sum + item;
            System.out.println("sum after:" + sum);

            return sum;

//            return Integer.sum(sum, item);
        });
        //等效
        Optional<Integer> optional1 = Stream.of(1, 2, 3, 4, 5).reduce((sum, item) ->
                Integer.sum(sum, item)
        );
        //等效
        Optional<Integer> optional2 = Stream.of(1, 2, 3, 4, 5).reduce(Integer::sum);
        System.out.println("integer = " + optional.orElse(-1));
        System.out.println("*****************************************");
        //給定初始值,第一個參數爲初始值,第二個參數爲stream的第一個元素,計算的結果賦值給下一輪計算的sum
        Integer reduce = Stream.of(1, 2, 3, 4, 5).reduce(5, (sum, item) -> {
            System.out.println("sum2 before:" + sum);
            System.out.println("item:" + item);
            sum = sum + item;
            System.out.println("sum2 after:" + sum);
            return sum;
        });
        //等效
        Integer reduce2 = Stream.of(1, 2, 3, 4, 5).reduce(0, (sum, item) ->
                Integer.sum(sum, item)
        );
        //等效
        Integer reduce3 = Stream.of(1, 2, 3, 4, 5).reduce(0, Integer::sum);
        System.out.println("reduce = " + reduce);


        System.out.println("*********************collect********************");
        List<Integer> toList = Stream.of(1, 2, 3, 4)
                .collect(Collectors.toList());
        List<Integer> toList2 = Stream.of(1, 2, 3, 4)
                .collect(Collectors.toCollection(ArrayList::new));
        System.out.println("toList: " + toList);

        Set<Integer> toSet = Stream.of(1, 2, 3, 4)
                .collect(Collectors.toSet());
        Set<Integer> toSet2 = Stream.of(1, 2, 3, 4)
                .collect(Collectors.toCollection(() -> new TreeSet()));
        System.out.println("toSet: " + toSet);

        //(value1, value2) -> value1  用前面的value覆蓋後面的value,保持不變
        List<User> userList = UserUtil.getUsers(5);
        userList.add(new User(2, "fjw"));
        Map<Integer, String> toMap = userList.stream()
                .collect(Collectors.toMap(User::getId, User::getName, (value1, value2) -> value1));
        System.out.println("(value1, value2) -> value1");
        toMap.forEach((k, v) -> System.out.println(k + "-" + v));

        // 對value值進行了限定不能爲null,不然拋出空指針異常
//        userList.add(new User(3, null));
        //(value1, value2) -> value2  用後面的value覆蓋前面的value
        Map<Integer, String> toMap2 = userList.stream()
                .collect(Collectors.toMap(User::getId, User::getName, (value1, value2) -> value2));
        System.out.println("(value1, value2) -> value2");
        toMap2.forEach((k, v) -> System.out.println(k + "-" + v));

        // 解決value值爲null方式
        userList.add(new User(4, null));
        Map<Integer, String> toMap3 = userList.stream()
                .collect(HashMap::new, (m, u) -> m.put(u.getId(), u.getName()), HashMap::putAll);
        toMap3.forEach((k, v) -> System.out.println(k + "-" + v));

        Optional<Integer> maxBy = Stream.of(1, 2, 3, 4)
                .collect(Collectors.maxBy(Comparator.comparingInt(o -> o)));
        System.out.println("maxBy:" + maxBy.get());

        Long counting = Stream.of(1, 2, 3, 4)
                .collect(Collectors.counting());
        System.out.println("counting:" +counting);

        //分割數據塊
        Map<Boolean, List<Integer>> partitioningBy = Stream.of(1, 2, 3, 4, 5)
                .collect(Collectors.partitioningBy(item -> item > 3));
        //partitioningBy : {false=[1, 2, 3], true=[4, 5]}
        System.out.println("partitioningBy : " + partitioningBy);

        Map<Boolean, Long> collect = Stream.of(1, 2, 3, 4)
                .collect(Collectors.partitioningBy(item -> item > 3, Collectors.counting()));
        System.out.println("collect: " + collect);

        //數據分組
        Map<Boolean, List<Integer>> groupingBy = Stream.of(1, 2, 3, 4, 5)
                .collect(Collectors.groupingBy(item -> item > 3));
        //partitioningBy : {false=[1, 2, 3], true=[4, 5]}
        System.out.println("groupingBy : " + groupingBy);

        //字符串
        String joining = Stream.of("a", "b", "c", "d")
                .collect(Collectors.joining(","));
        System.out.println(joining);

        String joining2 = Stream.of("a", "b", "c", "d")
                .collect(Collectors.joining(",", "[", "]"));
        System.out.println(joining2);

 

源碼參照Github

相關文章
相關標籤/搜索