Java8用了這麼久了,Stream 流用法及語法你都知道嗎?

1.簡介

Stream流 最全的用法
Stream 能用來幹什麼?用來處理集合,經過 使用Stream API 對集合數據進行操做,就相似於使用 SQL 執行的數據庫查詢,Stream API 提供了一種高效且易於使用的處理數據的方式面試

爲何用Java 8 Stream ?由於 操做簡單
爲何操做簡單?由於 Lambda 表達式,它極大的提升了編程效率和程序可讀性
怎麼操做流? 首先你的有個數據源(數組、集合),操做會產生新的流對象,原來的流對象不會改變
流用法有結束操做,這種代碼不是你寫了一個方法就執行一個方法,而是最後觸發結束操做的時候才統一執行的,collect、foreach 方法就是一種結束方法,詳情看代碼及結果參考 2.映射map、flatMap用法 部分數據庫

2.具體用法

2.1 建立流

// 集合建立流
        List<String> list = new ArrayList<>();
        // 獲取一個順序流
        Stream<String> listStream = list.stream();
        // 獲取一個並行流
        Stream<String> parallelListStream = list.parallelStream();

        // 數組建立流
        Integer[] nums = new Integer[] { 1, 2, 3, 4, 5 };
        Stream<Integer> arrStream = Arrays.stream(nums);
        arrStream.forEach(System.out::println);// 1 2 3 4 5

        // 靜態方法of建立流
        Stream<Integer> ofStream = Stream.of(1, 2, 3, 4, 5);
        ofStream.forEach(System.out::println);// 1 2 3 4 5

        // 靜態方法iterate 建立流
        Stream<Integer> iterateStream = Stream.iterate(1, (x) -> x + 10).limit(4);
        iterateStream.forEach(System.out::println); // 1 11 21 31

        // 靜態方法generate 建立流
        Stream<Double> generateStream = Stream.generate(Math::random).limit(2);
        generateStream.forEach(System.out::println);

2.2 操做流

1.過濾

filter:過濾流中的某些元素(能夠作一些基本的判空、替換、判斷邏輯操做)
limit(n):獲取n個元素,結果獲取幾個元素
skip(n):跳過n元素,配合limit(n)可實現分頁
distinct:經過流中元素的 hashCode() 和 equals() 去除重複元素編程

//filter 判空
     Stream<Integer> notNullStreamObj = Stream.of(1, 2, null, 4, 5, 6, 7, null, 2);
     Stream<Integer> notNullStream = notNullStreamObj.filter(i -> (null != i));
     notNullStream.forEach(System.out::println);//1 2 4 5 6 7 2

     //filter 邏輯判斷
     Stream<Integer> logicStreamObj = Stream.of(1, 2, null, 4, 5, 6, 7, null, 2);
     Stream<Integer> logicStream = logicStreamObj.filter(i -> (i != null && i > 5));
     logicStream.forEach(System.out::println); // 6 7

     //filter 替換
     Stream<String> strStreamObj = Stream.of("aa", "ab", null, "ac", "bd", "ee");
     Stream<String> strStream = strStreamObj.filter(str -> (null != str && str.contains("a")));
     strStream.forEach(System.out::println); // aa ab ac


     //skip 跳過
     Stream<String> skipStreamObj = Stream.of("aa", "ab", null, "ac", "bd", "ee");
     Stream<String> skipStream = skipStreamObj.skip(2);
     skipStream.forEach(System.out::println); // null ac bd ee

     //distinct 去重
     Stream<String> disStreamObj = Stream.of("aa", "ab", null, "ac", "aa", "ab", null, "ee");
     Stream<String> disStream = disStreamObj.distinct();
     disStream.forEach(System.out::println); // aa ab null ac ee

2.映射

map:接收一個函數做爲參數,該函數會被應用到每一個元素上,映射成一個新的元素。
flatMap:接收一個函數做爲參數,將流中的每一個值都換成另外一個流,而後把全部流鏈接成一個流。
peek:這個操做很騷,相似map只不過map 是Func函數,提供返回值,而peer是取出元素,Consumer表達式設值,我我的以爲沒啥區別呢,官方文檔提示:該方法主要用於調試,作一些消耗這個對象但不修改它的東西,沒啥事不要用
很想問一下 這倆map、flatMap 區別 ,細品,你細品,你細細品
map是將每一個元素 映射成一個新元素,除非你過濾了,不然不會改變元素個數
flatMap是將原流中的每一個值都變成另外一個流,而後把流合併串起來,必須有返回值,拼裝成新的流數組

//map 把包含a的元素,替換成| 注意,注意, 元素仍是一個總體,對每一個元素
     Stream<String> mapStreamObj = Stream.of("a,b,c", "a,e,f", "g,h,i");
     Stream<String> mapStream = mapStreamObj.map(str -> str.replaceAll(",", "|"));
     mapStream.forEach(System.out::println); // a|b|c a|e|f h|i|j

     //flatMap 能夠把元素 切分後,再按照新元素組成新的字符串
     Stream<String> flatMapStreamObj = Stream.of("a,b,c", "a,e,f", "g,h,i");
     Stream<String> flatMapStream = flatMapStreamObj.flatMap(str -> {
         String[] arr = str.split(",");
         Stream<String> result = Arrays.stream(arr);
         return result;
     });
     flatMapStream.forEach(System.out::println); //a b c d e f g h i


     System.out.println("1===========");
     Stream<String> peekStreamObj = Stream.of("a,b,c", "a,e,f", "g,h,i");
     Stream<String> peekStream = peekStreamObj.peek(e -> System.out.println("Filtered value: " + e))
             .map(String::toUpperCase)
             .peek(e -> System.out.println("Mapped value: " + e));
     System.out.println("2=========== peek代碼結束,可是日誌沒打印");
     Set<String> stringSet = peekStream.collect(Collectors.toSet());
     System.out.println("3=========== collect結束操做,代碼日誌打印");
     stringSet.forEach(System.out::println);

map執行結果

//看下執行結果,說明 collect纔是結束操做,代碼結束,可是並非真正結束
1===========
2=========== peek代碼結束,可是日誌沒打印
Filtered value: a,b,c
Mapped value: A,B,C
Filtered value: a,e,f
Mapped value: A,E,F
Filtered value: g,h,i
Mapped value: G,H,I
3=========== collect結束操做,代碼日誌打印
A,B,C
A,E,F
G,H,I

3.排序

sorted():天然排序,流中元素需實現Comparable接口
sorted(Comparator com):定製排序,自定義Comparator排序器
先構建一個User類app

public static class User {
       private String name;
       private Integer age;

       public User(String name, Integer age) {
           this.name = name;
           this.age = age;
       }

       public String getName() {
           return name;
       }

       public void setName(String name) {
           this.name = name;
       }

       public Integer getAge() {
           return age;
       }

       public void setAge(Integer age) {
           this.age = age;
       }

       @Override
       public String toString() {
           return "User{" +
                   "name='" + name + '\'' +
                   ", age=" + age +
                   '}';
       }
   }

而後 看下sort用法dom

//按字母排序
       Stream<String> sortStreamObj = Stream.of("a,e,f", "a,d,c", "a,b,i");
       Stream<String> sortStream = sortStreamObj.sorted();
       sortStream.forEach(System.out::println); //abi adc aef


       User u1 = new User("bb", 1);
       User u2 = new User("aa", 2);
       User u3 = new User("cc", 3);
       User u4 = new User("aa", 4);

       Set<User> userSet = Sets.newHashSet(u1, u2, u3, u4);
       Stream<User> userStream = userSet.stream().sorted(
               (obj1, obj2) -> {
                   if (obj1.getName().equals(obj2.getName())) {
                       //name相等 按age
                       return obj1.getAge() - obj2.getAge();
                   }
                   return obj1.getName().compareTo(obj2.getName());
               }
       );

       userStream.forEach(System.out::println);// u2 u4 u1 u3

sort 執行結果

a,b,i
a,d,c
a,e,f
User{name='aa', age=2}
User{name='aa', age=4}
User{name='bb', age=1}
User{name='cc', age=3}

4.流匹配

allMatch:接收一個 Predicate 函數,當流中每一個元素都符合該斷言時才返回true,不然返回false
noneMatch:接收一個 Predicate 函數,當流中每一個元素都不符合該斷言時才返回true,不然返回false
anyMatch:接收一個 Predicate 函數,只要流中有一個元素知足該斷言則返回true,不然返回false
findFirst:返回流中第一個元素
findAny:返回流中的任意元素
count:返回流中元素的總個數
max:返回流中元素最大值
min:返回流中元素最小值ide

List<Integer> numLists = Arrays.asList(3, 4, 5, 6, 10);
        // 所有匹配 - true
        boolean allMatch1 = numLists.stream().allMatch(e -> e > 2); //true
        System.out.println("allMatch1:" + allMatch1);

        // 所有匹配 - true
        boolean allMatch2 = numLists.stream().allMatch(e -> e > 5); //false
        System.out.println("allMatch2:" + allMatch2);

        // 所有都不符合 - true
        boolean noneMatch = numLists.stream().noneMatch(e -> e > 20); //true
        System.out.println("noneMatch:" + noneMatch);

        // 任一元素符合 - true
        boolean anyMatch = numLists.stream().anyMatch(e -> e > 4);  //true
        System.out.println("anyMatch:" + anyMatch);

        //返回第一個
        Integer findFirst = numLists.stream().findFirst().get(); //3
        System.out.println("findFirst:" + findFirst);

        //返回任一個
        Integer findAny = numLists.stream().findAny().get(); 
        System.out.println("findAny:" + findAny);

        //返回 count
        long count = numLists.stream().count(); //5
        System.out.println("count:" + count);

        //返回max
        Integer max = numLists.stream().max(Integer::compareTo).get(); //10
        System.out.println("max:" + max);

        //返回min
        Integer min = numLists.stream().min(Integer::compareTo).get();//3
        System.out.println("min:" + min);

匹配執行結果函數

allMatch1:true
allMatch2:false
noneMatch:true
anyMatch:true
findFirst:3
findAny:3
count:5
max:10
min:3

5.組合操做

Reduce 就是組合操做
Reduce(BinaryOperator accumulator) 沒有起始值,按照運算規則進行運算操做
解釋:第一次執行時,accumulator函數的第一個參數爲流中的第一個元素,第二個參數爲流中元素的第二個元素,按照函數進行操做;
第二次執行時,第一個參數爲第一次函數執行操做的結果,第二個參數爲流中的第三個元素;往下依次類推,返回Optinal 經過get()方法獲取結果
Reduce(T identity, BinaryOperator accumulator)含有初始值,第二個是第一個的變形,跟第一個方法對比,不一樣的是這次這個會接受一個identity參數,用來指定Stream循環的初始值。若是Stream爲空,就直接返回該值,特殊:該方法不會返回 Optionalthis

Optional sumResult = Stream.of(1, 2, 3, 4)
                .reduce((sum, item) -> {
                    System.out.println("sum : " + sum);
                    sum += item;
                    System.out.println("item: " + item);
                    System.out.println("sum+ : " + sum);
                    System.out.println("-----——---");
                    return sum;
                });
        System.out.println("========sumResult: " + sumResult.get());


        Integer sumDefineResult = Stream.of(1, 2, 3, 4)
                .reduce(100, (sum, item) -> {
                    System.out.println("sum : " + sum);
                    sum += item;
                    System.out.println("item: " + item);
                    System.out.println("sum+ : " + sum);
                    System.out.println("---——-----");
                    return sum;
                });
        System.out.println("========sumDefineResult: " + sumDefineResult);

reduce 執行結果調試

//下面是執行結果
//查看執行結果
sum : 1
item: 2
sum+ : 3
-----——---
sum : 3
item: 3
sum+ : 6
-----——---
sum : 6
item: 4
sum+ : 10
-----——---
========sumResult: 10
sum : 100
item: 1
sum+ : 101
---——-----
sum : 101
item: 2
sum+ : 103
---——-----
sum : 103
item: 3
sum+ : 106
---——-----
sum : 106
item: 4
sum+ : 110
---——-----
========sumDefineResult: 110

6. 收集轉換操做

這是個最最最最最基本的操做,10個流操做 9個都會使用到當前操做

collect(Collectors.toList()) 轉換List
collect(Collectors.toSet()) 轉換Set
Collectors.toMap(key, value) 轉換Map ,若是key重複,!!!報錯
Collectors.joining() join進行拼接
Collectors.groupingBy(key) 以Key爲map的 key分組
Collectors.partitioningBy(規則) 以規則分區 好比 >5 ,map key爲true,false

User s1 = new User("aa", 1);
        User s2 = new User("bb", 2);
        User s3 = new User("cc", 3);
        User s4 = new User("dd", 2);
        List<User> list = Arrays.asList(s1, s2, s3, s4);

        //轉換list
        List<Integer> ageList = list.stream().map(User::getAge).collect(Collectors.toList()); // [1, 2, 3]
        System.out.println(ageList.toString());

        //轉成set
        Set<Integer> ageSet = list.stream().map(User::getAge).collect(Collectors.toSet()); // [1, 2, 3]
        System.out.println(ageSet);

        //轉成map,注:key不能相同,不然報錯
        Map<String, Integer> userMap = list.stream().collect(Collectors.toMap(User::getName, User::getAge)); // {cc=10, bb=20, aa=10}
        System.out.println(userMap);

        //字符串分隔符鏈接
        String joinName = list.stream().map(User::getName).collect(Collectors.joining(",", "(", ")")); // (aa,bb,cc)
        System.out.println(joinName);

        //分組
        Map<Integer, List<User>> ageMap = list.stream().collect(Collectors.groupingBy(User::getAge));
        System.out.println(ageMap);

        //多重分組,先根據類型分再根據年齡分
        Map<Integer, Map<Integer, List<User>>> typeAgeMap = list.stream().collect(Collectors.groupingBy(User::getAge, Collectors.groupingBy(User::getAge)));
        System.out.println(typeAgeMap);

        //分區
        //分紅兩部分,true 一部分age大於2歲, false 一部分age小於等於2歲
        Map<Boolean, List<User>> partMap = list.stream().collect(Collectors.partitioningBy(v -> v.getAge() > 2));
        System.out.println(partMap);

collect 執行結果

[1, 2, 3, 2]
[1, 2, 3]
{dd=2, cc=3, bb=2, aa=1}
(aa,bb,cc,dd)
{1=[User{name='aa', age=1}], 2=[User{name='bb', age=2}, User{name='dd', age=2}], 3=[User{name='cc', age=3}]}
{1={1=[User{name='aa', age=1}]}, 2={2=[User{name='bb', age=2}, User{name='dd', age=2}]}, 3={3=[User{name='cc', age=3}]}}
{false=[User{name='aa', age=1}, User{name='bb', age=2}, User{name='dd', age=2}], true=[User{name='cc', age=3}]}

最後

你們看完有什麼不懂的能夠在下方留言討論,也能夠關注我私信問我,我看到後都會回答的。也歡迎你們關注個人公衆號:前程有光,金三銀四跳槽面試季,整理了1000多道將近500多頁pdf文檔的Java面試題資料,文章都會在裏面更新,整理的資料也會放在裏面。謝謝你的觀看,以爲文章對你有幫助的話記得關注我點個贊支持一下!

相關文章
相關標籤/搜索