1. 程式人生 > 實用技巧 >Stream中的常用操作詳解

Stream中的常用操作詳解

java8 Stream中的常用操作

一. 匹配、過濾、篩選操作

  1. 以下操作的入引數都是Predicate[核心是輸入一個值,返回一個布林值(true or false)].
  2. 流的中間操作和終止操作,簡單理解就是終止操作之後返回的不是流物件(其他物件或沒有返回值),中間操作返回的都是流物件(Stream)。
  3. 具體的操作案例
  • filter: 是一種流的中間操作

    List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
    stringList.stream()
        .filter(x -> x.length() > 3)
        .forEach(System.out::println);
    
  • anyMatch 是一種流的終止操作,與此用法相同的還有一個allMatch 和noneMatch,也是終止操作,區別是allMatch是所有匹配才返回true,anyMath是隻要有一個匹配就返回true, noneMatch 是沒有匹配到返回true。

     List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
     boolean match = stringList.stream().anyMatch(x -> x.contains("c"));
     System.out.println(match);
     boolean allMatch = stringList.stream().allMatch(x -> x.contains("c"));
     System.out.println(allMatch);
     boolean noMatch = stringList.stream().allMatch(x -> x.contains("c"));
     System.out.println(noMatch);
    
  • dropWhile: 刪除當前流中符號條件的資料,直到不滿足條件為止,即從流中的第一個元素開始匹配,如果滿足則繼續匹配,如果不滿足就不會再繼續象後匹配。

    List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
     stringList.stream()
         //匹配第一個元素是滿足條件的,第二個不滿足條件,後續就算是滿足條件的也不會被刪除
         .dropWhile(x -> x.length() < 5)
         .forEach(System.out::println);
    stringList.stream()
         //匹配第一個元素是不滿足條件的,後續就算是滿足條件的也不會被刪除
         .dropWhile(x -> x.length() < 3)
         .forEach(System.out::println);
    
  • takeWhile 與dropWhile類似,只是takeWhile是取出來元素生成新的流,dropWhile是刪除匹配的元素,用剩下的元素生成一個新的流

    List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
    stringList.stream()
        //匹配時前兩個滿足,第三個不滿足就會終止,即只取到前面兩個元素
        .takeWhile(x -> x.length() > 2)
        .forEach(System.out::println);
    

二. map相關操作

  1. map操作傳入的引數是Function[核心是輸入一個引數,返回一個值],map也是流的中間操作,map結果是一個新流
  2. 如果結果為空,則返回空流(empty stream)
  3. 具體的操作案例
  • map
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
stringList.stream()
    .filter(x -> x.length() > 3)
    .map(String::length)
    .forEach(System.out::println);
//- mapToInt  即通過一個ToIntFunction,返回一個IntStream
//- mapToDouble 即通過一個ToDoubleFunction,返回一個DoubleStream
//- mapToLong 即通過一個ToLongFunction,返回一個LongStream 
  • flatmap
List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
stringList.stream()
	.flatMap(x -> Stream.of(x.split("")))
	.forEach(System.out::println);
//- flatMapToInt  即通過一個Function,返回一個IntStream
//- flatMapToDouble 即通過一個Function,返回一個DoubleStream
//- flatMapToLong 即通過一個Function,返回一個LongStream 

三.排序、最值、去重操作

  1. 排序有兩個方法,sorted()和sorted(Comparator<? super T> comparator),前者是預設排序,後者是按特定的比較器實現排序,排序也是一種中間操作

  2. max和min是兩個求最值的操作,是一種流的終止操作,返回的是一個最值得Optional

  3. 去重是distinct操作,也是中間操作

  4. 案例:

    • sorted
    //sorted 
    List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
    stringList.stream()
         .sorted()
         .forEach(System.out::println);
    //特定比較器排序
    stringList.stream()
        //Comparator.comparingInt(String::length) 等價於lambada表示式:(x,y) -> x.length() - y.length()
    	 .sorted(Comparator.comparingInt(String::length))
         .forEach(System.out::println);
    
    • max、min 都是傳入一個比較器,返回一個對應得Optional
    List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
    String val = stringList.stream()
        		//換成min也同理
                .max(Comparator.comparingInt(String::length))
        		.orElse(null);
    System.out.println(val);
    
    • distinct
    List<String> strList = List.of("java","pathon", "go", "c++", "c#", "php", "java", "go");
    strList.stream().distinct().forEach(System.out::println);
    

四. 數量相關操作

  1. 計數操作:count終止操作,返回的是當前流中的元素個數

  2. 跳過操作:skip 中間操作,返回當前流中跳過指定元素個數後剩下的元素組成的新流

  3. 取數操作:limit 中間操作,返回當前流中前n個元素組成的新的流,n為正整數 是limit函式的引數

  4. 案例

    • count

        List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
        long count = stringList.stream().filter(x -> x.length() > 3).count();
        System.out.println(count);
      
    • skip

      List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
      stringList.stream().skip(2).forEach(System.out::println);
      
    • limit

      List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
      stringList.stream().limit(2).forEach(System.out::println);
      

五.查詢操作(findAny和findFirst)

  1. 查詢操作都屬於終止操作,都無入參

  2. 一般搭配篩選和過濾等中間操作

  3. 案例

    • findFirst

      List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
      String val = stringList.stream()
          .findFirst()
          .orElse(null);
      System.out.println(val);
      
      //搭配filter,sorted
      String value = stringList.stream()
          .filter(x -> x.length() > 2)
          .sorted()
          .findFirst()
          .orElse(null);
      System.out.println(value);
      
    • findAny

      List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
      String val = stringList.stream()
          .findAny()
          .orElse(null);
      System.out.println(val);
      
      //搭配filter,sorted
      String value = stringList.stream()
          .filter(x -> x.length() > 2)
          .sorted()
          .findAny()
          .orElse(null);
      System.out.println(value);
      

六.遍歷操作(peek和foreach)

  1. peek是中間操作,一般用於程式除錯,最終結果是一個流物件

  2. foreach是終止操作,無返回值

  3. 案例

    List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
    stringList.stream()
        .peek(System.out::println)
        .filter(x -> x.length() > 4)
        .forEach(System.out::println);
    

七. collect操作

  1. collect操作有兩個方法,一個是collect(Collector<? super T, A, R> collector), 一個是collect(Supplier supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner)。

  2. Collector<? super T, A, R> collector 是一個介面,該介面對應方法有以下幾個

  3. 常用操作案例

    List<String> stringList = List.of("java","pathon", "go", "c++", "c#", "php");
    //toList
    List<String> list = stringList.stream()
        .filter(x -> x.length() > 4)
        .collect(Collectors.toList());
    //toSet
    Set<String> set = stringList.stream()
        .filter(x -> x.length() > 4)
        .collect(Collectors.toSet());
    //toMap
    Map<String, Integer> map = stringList.stream()
        .filter(x -> x.length() > 4)
        .collect(Collectors.toMap(x -> x, String::length));
    //joining
    String str = stringList.stream()
        .filter(x -> x.length() > 4)
        .collect(Collectors.joining(","));
    String str2 = stringList.stream()
        .filter(x -> x.length() > 4)
        .collect(Collectors.joining(",","{","}"));
    //groupingBy 
    List<String> strList = List.of("java","pathon", "go", "c++", "c#", "php", "java", "go");
    Map<String, List<String>> listMap = strList.stream()
        .collect(Collectors.groupingBy(x -> x));
    //partitioningBy
    List<String> strList = List.of("java","pathon", "go", "c", "c", "php", "java", "go");
    Map<Boolean, List<String>> booleanListMap =strList.stream()
        .collect(Collectors.partitioningBy(x -> x.contains("c")));
    //一般操作 即用指定的函式實現Collectors操作
    List<String> strList = List.of("java","pathon", "go", "c", "c", "php", "java", "go");
    List<String> list = strList.stream()
        .distinct()
        .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
    

八. reduce操作

  1. reduce 操作實現的是從通過當前流中元素根據指定的計算生成一個新的值,計算可以是count、min和max等方法,概念比較抽象,多練習。

  2. reduce和collect一樣都有一般操作,兩者類似,就是按照對應的介面實現來完成相應的操作。

  3. 常用案例

    // 用reduce(BinaryOperator<T> accumulator) BinaryOperator是傳入兩個相同的值,返回一個跟入參型別一樣的值,此方法返回的是Optional
    List<String> strList = List.of("java","pathon", "go", "c", "c", "php", "java", "go");
    String reduce = strList.stream().reduce((x, y) -> x + y).orElse("");
    
    //用reduce(T identity, BinaryOperator<T> accumulator) 此方法返回指定型別T的值,即在指定型別T,值為identity的基礎上進行對應的操作後得到的結果,BinaryOperator是輸入兩個入參型別都為T,返回值也為T
    String reduce1 = strList.stream().reduce("@@@", (x, y) -> x + y);
    
    //用reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner) 此方法返回的是指定型別U的值,BiFunction<U, ? super T, U> 其核心為輸入兩個值U,T,返回的是入參中的U
    int reduce2 = strList.stream()
        .reduce(0, (x, y) -> x + y.length(), Integer::sum);
    

stream的建立見之前的基礎篇,後續再詳解函數語言程式設計介面,這塊內容後續也會涉及Flux,Spring Web Flux。