Java 8之stream進階

前言:

上一篇文章 Java 8之stream介紹和使用 中講解了stream的定義和用法,簡單介紹幾個最基本最經常使用的方法,其實stream還有更強大的功能,這篇文章就會給你們介紹stream的進階用法。segmentfault


篩選:

在上一篇文章中咱們介紹了使用filter方法來篩選元素,filter方法接受一個Predicate類型的參數,咱們能夠傳入一個Lamada表達式或者方法引用,原理在 Java 8之方法引用和Lambda表達式 中已經將結果。咱們其實是傳入了一個條件,而後篩選出符合條件的元素,例以下面的這行代碼就是篩選出年齡大於20的人。數組

List<Person> list = peoples.stream().filter(person -> person.getAge()>20).collect(toList());

實際上stream還有別的方法能夠進行篩選,下面咱們來介紹幾個經常使用的。函數

  • distinct,這個方法能夠幫助咱們去重code

    List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
    numbers.stream().filter(i -> i % 2 == 0).distinct().forEach(System.out::println);
  • limit,這個方法可讓咱們只取stream中的前幾個,值得注意的是當咱們用Set集合來存儲元素時,由於Set是無序的,因此每次咱們取到的前幾個元素也會是無序的。對象

    List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
    numbers.stream().limit(3).forEach(System.out::println);
  • skip,這個方法可讓咱們跳過元素,跳過多少個元素由咱們指定。ip

    List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
    numbers.stream().skip(3).forEach(System.out::println);

映射:

咱們常常遇到從對象中抽取本身須要的元素放入一個新的類型的集合中的狀況,這就是映射操做,而stream在這方面也提供了很是強大的支持。字符串

  • map,這個方法接受一個Lambda表達式,它會遍歷整個流把這個函數做用到每一個元素上,而後把輸出的結果放到一個新流中。get

    // 獲取每一個元素的name屬性放入一個新流中,而後把這個流轉爲List類型。
    List<Person> names = peoples.stream().map(Person::getName).collect(toList());
    // 獲取每一個元素的字符串長度放入新流中,而後轉爲List類型。
    List<String> words = Arrays.asList("AA", "B", "CCC", "DDDDDD");
    List<Integer> wordLengths = words.stream().map(String::length).collect(toList());
  • flatmap,這個方法比較特殊,它的做用是把多個相同類型的流連成一個流,咱們看下面的代碼,目的是爲了把集合中的字符串都拆成單個字符而後放到一個集合,可是若是直接用map方法的話返回的ListString[]類型的,這是由於word.split("")返回的結果就是這個類型的。string

    List<String> words = Arrays.asList("Hello", "world");
    List<String[]> list = words.stream().map(word -> word.split("")).collect(toList());

    在這裏要提到Arrays.stream()這個方法,它的做用是接受一個數組,而後把這個數組裏的元素轉爲一個流,因此咱們能夠嘗試使用這個方法來改進下上面的代碼。可是咱們發現仍是有問題,返回集合類型是Stream<String>,由於map(Arrays::stream)把數組裏的每一個元素都弄成了一個流。it

    List<String> words = Arrays.asList("Hello", "world");
    List<Stream<String>> list = words.stream().map(word -> word.split(""))
        .map(Arrays::stream).collect(toList());

    如今flatmap的做用就出來了,咱們把代碼改進下,改爲使用flatmap接受Arrays::stream,它的做用正是在上面map(Arrays::stream)的基礎上把集合裏的流裏面的元素合併成一個流,因此返回的List類型就是String類型的。

    List<String> words = Arrays.asList("Hello", "world");
    List<String> list = words.stream().map(word -> word.split(""))
        .flatmap(Arrays::stream).collect(toList());

匹配:

stream一樣也提供了不少方法來檢查集合中是否包含了某個指定的值。注意,這些方法都屬於 終端操做 ,也就是說調用了這些方法就會關閉流。

  • allMatch

    List<String> numbers = Arrays.asList("Hello", "World");
    boolean flag = numbers.stream().allMatch(string -> string.contains("z"));
    System.out.println(flag);
  • anyMatch,這個方法會檢查流中是否至少有一個元素匹配給定的值,返回一個boolean值。

    List<String> numbers = Arrays.asList("Hello", "World");
    boolean flag = numbers.stream().anyMatch(string -> string.contains("z"));
    System.out.println(flag);
  • noneMatch,這個方法則是和allMatch方法作相反的操做。

    List<String> numbers = Arrays.asList("Hello", "World");
    boolean flag = numbers.stream().noneMatch(string -> string.contains("z"));
    System.out.println(flag);

查找:

對於集合的操做最重要的就是從中查找符合條件的數據了,咱們來看下面的方法。

  • findAny,這個方法須要配合filter方法使用,返回把篩選出來的第一個元素。注意,這裏返回的是Optional類型的對象,這個對象是Java 8新增的專門爲了防止返回數據的時候遇到null的狀況,後續再做詳細瞭解,目前只須要知道它有個isPresent方法來判斷元素是否爲空,get方法用來取值。

    List<String> numbers = Arrays.asList("Hello", "World");
    Optional<String> optional= numbers.stream().filter(string -> string.contains("l")).findAny();
    if(optional.isPresent()){
        System.out.println(optional.get());
    }
  • findFirst,這個方法是用來取流中第一個元素的,目前看來好像沒什麼用,可是有時候咱們可能會對流進行復雜的篩選,再選取篩選後的流中第一個元素。

    List<String> numbers = Arrays.asList("Hello", "World");
    Optional<String> optional= numbers.stream().findFirst();
    System.out.println(optional.toString());

歸約:

歸約就是把整個流歸約成一個值的操做,好比求集合中最大的元素、全部元素值的和之類的操做。

  • reduce,這個方法就是用來對元素的值進行操做的,咱們這裏作加法運算。它接受兩個參數,第一個是初始值,就是開始計算前就已經有一個數值了。第二個參數是一個Lambda表達式,用來對各個元素作計算。

    List<Integer> list = Arrays.asList(1,2,3,4,5);
    int sum = list.stream().reduce(0,(a,b) -> a - b);
    System.out.println(sum);

    在Java 8中Integer中新增了一個sum方法,它的做用和上面的Lambda表達效果同樣,因此咱們可使用這個方法的方法引用來簡化代碼。

    List<Integer> list = Arrays.asList(1,2,3,4,5);
    int sum = list.stream().reduce(0,Integer::sum);
    System.out.println(sum);

    咱們還能夠用這個方法來求最大值和最小值,在Integer中還新增了minmax方法,等同於(x, y) -> x < y ? x : y(x, y) -> x > y ? x : y,這樣咱們就能夠求出流中的最大值和最小值了。

    Optional<Integer> min = numbers.stream().reduce(Integer::min);
    Optional<Integer> min = numbers.stream().reduce(Integer::max);

以上就是stream的篩選、查找、匹配和歸約操做中比較經常使用的方法了,下面還會介紹分組、分區等功能。

相關文章
相關標籤/搜索