一篇文章帶你瞭解Java Stream流

一、Stream流引入

Lambda表達式,基於Lambda所帶來的函數式編程,又引入瞭一個全新的Stream概念,用於解決集合類庫既有的鼻端。(Lambda表達式詳解在上篇博客內容)

現有一個需求:

將list集合中姓張的元素過濾到一個新的集合中

然後將過濾出來的姓張的元素中,再過濾出來長度為3的元素,存儲到一個新的集合中

1.用常規方法解決需求

        // 已知的知識來解決需求
        List<String> list1 = new ArrayList<>();
        list1.add("張老三");
        list1.add("張小三");
        list1.add("李四");
        list1.add("趙五");
        list1.add("張六");
        list1.add("王八");
        ArrayList<String> list2 = new ArrayList<>();
        // 1.將list集合中姓張的元素過濾到一個新的集合中
        for(String name : list1){
            if(name.startsWith("張")){
                list2.add(name);
            }
        }
        ArrayList list3 = new ArrayList();
        for (String name : list2) {
            if (name.length() == 3){
                list3.add(name);
            }
        }
        System.out.println(list3);

        輸出結果:
            [張顏宇, 張三豐]

2.用Stream流操作集合,獲取流,過濾操作,打印輸出

list1.stream().filter((String name)->name.startsWith("張")).filter((String name)->name.length()==3).forEach((String name)->{
            System.out.println("符合條件的姓名:" + name);
        });

( 看不懂沒關系,下面會講到該方法,這裡隻是用來引入的)

二、Stream流的格式

Stream<T> filter(Predicate<? super T> predicate);
            -----> 參數:public interface Predicate<T>  (函數式接口)
                    ----> 抽象方法:boolean test(T t);
            -----> 參數:public interface Consumer<T>  (函數式接口)
                    ----> 抽象方法:boolean test(T t);

整體代碼看來:流式思想 類似於 工廠車間的“流水線”

( 看不懂沒關系,下面會講到該方法,這裡隻是用來引入的)

三、獲取流

根據集合來獲取:

根據Collection獲取流:

Collection接口中有一個stream()方法,可以獲取流

default Stream<E> stream()

1.根據List獲取流

2.根據Set獲取流

3.根據Map獲取流

3.1根據Map集合的鍵來獲取流

3.2根據Map集合的值獲取流

3.3根據Map集合的鍵值對對象獲取流

4.根據數組獲取流

代碼演示:

1.根據List集合獲取流

        // 創建List集合
        List<String> list = new ArrayList<>();
        list.add("張老三");
        list.add("張小三");
        list.add("李四");
        list.add("趙五");
        list.add("張六");
        list.add("王八");
        Stream<String> stream1 = list.stream();

2.根據Set集合獲取流

        // 創建List集合
        Set<String> set = new HashSet<>();
        list.add("張老三");
        list.add("張小三");
        list.add("李四");
        list.add("趙五");
        list.add("張六");
        list.add("王八");
        Stream<String> stream2 = set.stream();

3.根據Map集合獲取流

        // 創建Map集合
        Map<Integer,String> map = new HashMap<>();
        map.put(1,"張老三");
        map.put(2,"張小三");
        map.put(3,"李四");
        map.put(4,"趙五");
        map.put(5,"張六");
        map.put(6,"王八");
        // 3.1根據Map集合的鍵獲取流
        Set<Integer> map1 = map.keySet();
        Stream<Integer> stream3 = map1.stream();
        // 3.2根據Map集合的值獲取流
        Collection<String> map2 = map.values();
        Stream<String> stream4 = map2.stream();
        // 3.3根據Map集合的鍵值對對象獲取瑞
        Set<Map.Entry<Integer, String>> map3 = map.entrySet();
        Stream<Map.Entry<Integer, String>> stream5 = map3.stream();

4.根據數組獲取流

        // 根據數組獲取流
        String[] arr = {"張顏宇","張三","李四","趙五","劉六","王七"};
        Stream<String> stream6 = Stream.of(arr);

四、Stream流的常用方法

Stream流的常用方法:

終結方法:返回值類型不再是Stream接口本身類型的方法,例如:forEach方法和count方法

非終結方法/延遲方法:返回值類型仍然是Stream接口自身類型的方法,除瞭終結方法都是延遲方法。例如:filter,limit,skip,map,conat

方法名稱方法作用方法種類是否支持鏈式調用count統計個數終結方法否forEach逐一處理終結方法否filter過濾函數拼接是limit取用前幾個函數拼接是skip跳過前幾個函數拼接是map映射函數拼接是concat組合函數拼接是

方法演示:

1.count方法:

long count (); 統計流中的元素,返回long類型數據

        List<String> list = new ArrayList<>();
        list.add("張老三");
        list.add("張小三");
        list.add("李四");
        list.add("趙五");
        list.add("張六");
        list.add("王八");
        long count = list.stream().count();
        System.out.println("集合中的元素個數是:" + count);

        輸出結果:
            集合中的元素個數是:6

2.filter方法:

Stream<T> filter(Predicate<? super ?> predicate); 過濾出滿足條件的元素

參數Predicate:函數式接口,抽象方法:boolean test (T t)

Predicate接口:是一個判斷接口

        // 獲取stream流
        Stream<String> stream = Stream.of("張老三", "張小三", "李四", "趙五", "劉六", "王七");
        // 需求:過去出姓張的元素
        stream.filter((String name)->{
            return name.startsWith("張");
        }).forEach((String name)->{
            System.out.println("流中的元素" + name);
        });

(上面引入Stream流時,就用到瞭這個方法)

3.forEach方法

void forEach(Consumer<? super T> action):逐一處理流中的元素

參數 Consumer<? super T> action:函數式接口,隻有一個抽象方法:void accept(T t);

註意:

1.此方法並不保證元素的逐一消費動作在流中是有序進行的(元素可能丟失)

2.Consumer是一個消費接口(可以獲取流中的元素進行遍歷操作,輸出出去),可以使用Lambda表達式

        List<String> list = new ArrayList<>();
        list.add("張老三");
        list.add("張小三");
        list.add("李四");
        list.add("趙五");
        list.add("張六");
        list.add("王八");
        // 函數模型:獲取流 --> 註意消費流中的元素
        list.stream().forEach((String name)->{
            System.out.println(name);
        });

        輸出結果:
            張老三
            張小三
            李四
            趙五
            張六
            王八

4.limit方法

Stream<T> limit(long maxSize); 取用前幾個元素

註意:

參數是一個long 類型,如果流的長度大於參數,則進行截取;否則不進行操作

        // 獲取流的長度
        Stream<String> stream1 = Stream.of("張老三", "張小三", "李四", "趙五", "劉六", "王七");
        // 需求:保留前三個元素
        stream1.limit(3).forEach((String name)->{
            System.out.println("流中的前三個元素是:" + name);
        });

        輸出結果:
            流中的前三個元素是:張老三
            流中的前三個元素是:張小三
            流中的前三個元素是:李四

5.map方法

<r> Stream <R> map(Function<? super T,? exception R> mapper;

參數Function<T,R>:函數式接口,抽象方法:R apply(T t);

Function<T,R>:其實就是一個類型轉換接口(T和R的類型可以一致,也可以不一致)

        // 獲取Stream流
        Stream<String> stream1 = Stream.of("11","22","33","44","55");
        // 需求:把stream1流中的元素轉換為int類型
        stream1.map((String s)->{
           return Integer.parseInt(s); // 將String類型的s進行轉換為Integer類型的元素,並返回
        }).forEach((Integer i)->{
            System.out.println(i);  // 將轉換後的int類型的元素逐一輸出
        });

        輸出結果:
            11
            22
            33
            44
            55

6.skip方法

Stream<T> skip(long n); 跳過前幾個元素

註意:

如果流的當前長度大於n,則跳過前n個,否則將會得到一個長度為0的空流

        // 獲取stream流
        Stream<String> stream = Stream.of("張老三", "張小三", "李四", "趙五", "劉六", "王七");
        stream.skip(3).forEach((String name)->{
            System.out.println("跳過前三個,打印剩下的" + name);
        });
      

  輸出結果:
            跳過前三個,打印剩下的趙五
            跳過前三個,打印剩下的劉六
            跳過前三個,打印剩下的王七

7.concat方法

public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)

–> 合並兩個流

         Stream<String> stream1 = Stream.of("11","22","33","44","55");
        Stream<String> stream2 = Stream.of("張顏宇", "張三", "李四", "趙五", "劉六", "王七");
        // 需求:合並兩個流
        Stream<String> stream = Stream.concat(stream1,stream2);
        stream.forEach((String name)->{
            System.out.print(name);
        });

        輸出結果:
            1122334455張顏宇張三李四趙五劉六王七

五、收集Stream流

Stream流中提供瞭一個方法,可以把流中的數據收集到單例集合中

<R, A> R collect(Collector<? super T, A, R> collector); 把流中的數據手機到單列集合中

返回值類型是R。R指定為什麼類型,就是手機到什麼類型的集合

參數Collector<? super T, A, R>中的R類型,決定把流中的元素收集到哪個集合中

參數Collector如何得到 ?,可以使用 java.util.stream.Collectors工具類中的靜態方法:

– public static <T> Collector<T, ?, List<T>> toList():轉換為List集合

– public static <T> Collector<T, ?, Set<T>> toSet() :轉換為Set集合

        List<String> list2 = new ArrayList<>();
        list2.add("張老三");
        list2.add("張小三");
        list2.add("李四");
        list2.add("趙五");
        list2.add("張六");
        list2.add("王八");
        // 需求:過濾出姓張的並且長度為3的元素
        Stream<String> stream = list2.stream().filter((String name) -> {
            return name.startsWith("張");
        }).filter((String name) -> {
            return name.length() == 3;
        });
        // stream 收集到單列集合中
        List<String> list = stream.collect(Collectors.toList());
        System.out.println(list);
        // stream 手機到單列集合中
        Set<String> set = stream.collect(Collectors.toSet());
        System.out.println(set);

總結

本片文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!

推薦閱讀: