java8新特性——Stream API

  Java8中有兩大最爲重要得改變,其一時Lambda表達式,另外就是 Stream API了。在前面幾篇中簡單學習了Lambda表達式得語法,以及函數式接口。本文就來簡單學習一下Stream API(java.util.stream.*)。java

  Stream 是 Java8中處理集合得關鍵抽象概念,他能夠指定你但願對集合進行得操做,能夠執行很是複雜得查找、過濾和映射數據等操做。使用Stream API對集合數據進行操做,就相似使用SQL執行得數據庫查詢。也可使用S他ream API 來並行執行操做。簡而言之,Stream API 提供了一種高效且易於使用得處理數據得方式。數據庫

  在Stream操做過程當中,能夠對數據流作過濾,排序,切片等操做,可是操做以後會產生一個新的流,而數據源則不會發生改變。api

 

1、什麼是 Stream數組

  Stream是數據渠道,用於操做數據源(集合,數組等)所生成得元素序列。而集合講得是數據,流講得是計算。網絡

  注意:dom

    ①. Stream 本身不會存儲元素。ide

    ②. Stream 不會改變源對象。相反,它會返回一個持有結果得新Stream函數

    ③. Stream 操做時延遲執行得,這意味着它們會等到須要結果時才執行。(延遲加載)學習

 

2、Stream 操做的三個步驟ui

  1). 建立 Stream

    一個數據源(集合,數組),獲取一個流。

  2). 中間操做

    一箇中間操做鏈,對數據源的數據進行處理。

  3). 終止操做

    一個終止操做,執行中間操做鏈,併產生結果。

 

3、建立Stream 的四種方式

  1). 經過Collection得Stream()方法(串行流)或者 parallelStream()方法(並行流)建立Stream。

 1   /**
 2      * 建立 Stream的四種方式
 3      * 1.經過Collection得Stream()方法(串行流)
 4             或者 parallelStream()方法(並行流)建立Stream
 5      */
 6     @Test
 7     public void test1 () {
 8         
 9         //1. 經過Collection得Stream()方法(串行流)
10         //或者 parallelStream()方法(並行流)建立Stream
11         List<String> list = new ArrayList<String>();
12         Stream<String> stream1 = list.stream();
13         
14         Stream<String> stream2 = list.parallelStream();
15         
16     }

 

  2).經過Arrays中得靜態方法stream()獲取數組流

 1     /**
 2      * 建立 Stream的四種方式
 3      * 2. 經過Arrays中得靜態方法stream()獲取數組流
 4      */
 5     @Test
 6     public void test2 () {
 7         
 8         //2. 經過Arrays中得靜態方法stream()獲取數組流
 9         IntStream stream = Arrays.stream(new int[]{3,5});
10         
11     }

 

  3). 經過Stream類中得 of()靜態方法獲取流

 1     /**
 2      * 建立 Stream的四種方式
 3      * 3. 經過Stream類中得 of()靜態方法獲取流
 4      */
 5     @Test
 6     public void test3 () {
 7         
 8         //3. 經過Stream類中得 of()靜態方法獲取流
 9         Stream<String> stream = Stream.of("4645", "huinnj");
10         
11     }

 

  4). 建立無限流(迭代、生成)

 1 /**
 2      * 建立 Stream的四種方式
 3      * 4. 建立無限流(迭代、生成)
 4      */
 5     @Test
 6     public void test4 () {
 7         
 8         //4. 建立無限流
 9         //迭代(須要傳入一個種子,也就是起始值,而後傳入一個一元操做)
10         Stream<Integer> stream1 = Stream.iterate(2, (x) -> x * 2);
11         
12         //生成(無限產生對象)
13         Stream<Double> stream2 = Stream.generate(() -> Math.random());
14         
15     }

 

4、Stream 中間操做

  多箇中間操做能夠鏈接起來造成一個流水線,除非流水線上觸發終止操做,不然中間操做不會執行任何得處理!而終止操做時一次性所有處理,稱爲‘延遲加載’

  1). 篩選與切片

    ①. filter —— 接收Lambda ,從流中排除某些元素。

 1     /**
 2      * 篩選與切片
 3      *  filter —— 接收Lambda ,從流中排除某些元素。
 4      *  
 5      */
 6     @Test
 7     public void test5 () {
 8         //內部迭代:在此過程當中沒有進行過迭代,由Stream api進行迭代
 9         //中間操做:不會執行任何操做
10         Stream<Person> stream = list.stream().filter((e) -> {
11             System.out.println("Stream API 中間操做");
12             return e.getAge() > 30;
13         });
14         
15         //終止操做:只有執行終止操做纔會執行所有。即:延遲加載 
16         stream.forEach(System.out :: println);
17     
18     }

  執行上面方法,獲得下面結果。

Person [name=張三, sex=男, age=76]
Stream API 中間操做
Stream API 中間操做
Person [name=王五, sex=男, age=35]
Stream API 中間操做
Stream API 中間操做
Person [name=錢七, sex=男, age=56]
Stream API 中間操做
Person [name=翠花, sex=女, age=34]

  咱們,在執行終止語句以後,一邊迭代,一邊打印,而咱們並無去迭代上面集合,其實這是內部迭代,由Stream API 完成。

  下面咱們來看看外部迭代,也就是咱們人爲得迭代。

1   @Test
2     public void test6 () {
3         //外部迭代
4         Iterator<Person> it = list.iterator();
5         while (it.hasNext()) {
6             System.out.println(it.next());
7         }
8     
9     }

 

    ②. limit —— 截斷流,使其元素不超過給定數量。

 

 1     /**
 2      * limit —— 截斷流,使其元素不超過給定數量。
 3      */
 4     @Test
 5     public void test7 () {
 6         //過濾以後取2個值
 7         list.stream().filter((e) -> e.getAge() >30 ).
 8         limit(2).forEach(System.out :: println);
 9     
10     }

  在這裏,咱們能夠配合其餘得中間操做,並截斷流,使咱們能夠取得相應個數得元素。並且在上面計算中,只要發現有2條符合條件得元素,則不會繼續往下迭代數據,能夠提升效率。

 

  2). 跳過元素

    skip(n),返回一個扔掉了前n個元素的流。若流中元素不足n個,則返回一個空,與limit(n)互補。

 1     /**
 2      * skip(n)—— 跳過元素,返回一個扔掉了前n個元素的流。
 3      * 若流中元素不足n個,則返回一個空,與limit(n)互補。
 4      */
 5     @Test
 6     public void test8 () {
 7         //跳過前2個值
 8         list.stream().skip(2).forEach(System.out :: println);
 9     
10     }
11      

 

   3).  篩選

    distinct 經過流所生成元素的hashCode()和equals()去除重複元素

 

1     /**
2      * distinct —— 篩選,經過流所生成元素的hashCode()和equals()去除重複元素
3      */
4     @Test
5     public void test9 () {
6         
7         list.stream().distinct().forEach(System.out :: println);
8     
9     }

 

  注意:distinct 須要實體中重寫hashCode()和 equals()方法纔可使用

 

  4). 映射

    ① . map ,將元素轉換成其餘形式或者提取信息。接收一個函數做爲參數,該函數會被應用到每一個元素上,並將其映射成一個新的元素。

 

 1     /**
 2      * map —— 映射 ,將元素轉換成其餘形式或者提取信息。接收一個函數做爲參數,該函數會被應用到每一個元素上,並將其映射成一個新的元素。
 3      */
 4     @Test
 5     public void test10 () {
 6         //將流中每個元素都映射到map的函數中,每一個元素執行這個函數,再返回
 7         List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
 8         list.stream().map((e) -> e.toUpperCase()).forEach(System.out::printf);
 9     
10         //獲取Person中的每個人得名字name,再返回一個集合
11         List<String> names = this.list.stream().map(Person :: getName).
12             collect(Collectors.toList());
13     }

 

 

    ② . flatMap —— 接收一個函數做爲參數,將流中的每一個值都換成一個流,而後把全部流鏈接成一個流

 

 

 1     /**
 2      * flatMap —— 接收一個函數做爲參數,將流中的每一個值都換成一個流,而後把全部流鏈接成一個流
 3      */
 4     @Test
 5     public void test11 () {
 6         StreamAPI_Test s = new StreamAPI_Test();
 7         List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
 8         list.stream().flatMap((e) -> s.filterCharacter(e)).forEach(System.out::println);
 9         
10         //若是使用map則須要這樣寫
11         list.stream().map((e) -> s.filterCharacter(e)).forEach((e) -> {
12             e.forEach(System.out::println);
13         });
14     }
15     
16     /**
17      * 將一個字符串轉換爲流
18      * @param str
19      * @return
20      */
21     public Stream<Character> filterCharacter(String str){
22         List<Character> list = new ArrayList<>();
23         for (Character ch : str.toCharArray()) {
24             list.add(ch);
25         }
26         return list.stream();
27     }

 

  其實map方法就至關於Collaction的add方法,若是add的是個集合得話就會變成二維數組,而flatMap 的話就至關於Collaction的addAll方法,參數若是是集合得話,只是將2個集合合併,而不是變成二維數組。

 

  5). 排序

     sorted有兩種方法,一種是不傳任何參數,叫天然排序,還有一種須要傳Comparator 接口參數,叫作定製排序。

 

 

 1     /**
 2      * sorted有兩種方法,一種是不傳任何參數,叫天然排序,還有一種須要傳Comparator 接口參數,叫作定製排序。
 3      */
 4     @Test
 5     public void test12 () {
 6         // 天然排序
 7         List<Person> persons = list.stream().sorted().collect(Collectors.toList());
 8         
 9         //定製排序
10         List<Person> persons1 = list.stream().sorted((e1, e2) -> {
11             if (e1.getAge() == e2.getAge()) {
12                 return 0;
13             } else if (e1.getAge() > e2.getAge()) {
14                 return 1;
15             } else {
16                 return -1;
17             }
18         }).collect(Collectors.toList());
19     }

 

 

 

5、Stream 終止操做

  1). 查找與匹配

    首先咱們先建立一個集合。

 

 1         List<Person> persons = Arrays.asList(
 2             new Person("張三", "男", 76, Status.FREE),
 3             new Person("李四", "女", 12, Status.BUSY),
 4             new Person("王五", "男", 35, Status.BUSY),
 5             new Person("趙六", "男", 3, Status.FREE),
 6             new Person("錢七", "男", 56, Status.BUSY),
 7             new Person("翠花", "女", 34, Status.VOCATION),
 8             new Person("翠花", "女", 34, Status.FREE),
 9             new Person("翠花", "女", 34, Status.VOCATION)
10             );

 

    ①. allMatch —— 檢查是否匹配全部元素。

 

1     /**
2      * allMatch —— 檢查是否匹配全部元素。
3      * 判斷全部狀態是否都是FREE
4      */
5     @Test
6     public void test13 () {
7          boolean b = persons.stream().allMatch((e) -> Status.FREE.equals(e.getStatus()));
8          System.out.println(b);
9     }

 

 

 

    ②. anyMatch —— 檢查是否至少匹配全部元素。

 

1     /**
2      * anyMatch —— 檢查是否至少匹配全部元素。
3      * 判斷是否有一個是FREE
4      */
5     @Test
6     public void test14 () {
7          boolean b = persons.stream().anyMatch((e) -> Status.FREE.equals(e.getStatus()));
8          System.out.println(b);
9     }

 

 

 

    ③. noneMatch —— 檢查是否沒有匹配全部元素。

 

1     /**
2      * noneMatch —— 檢查是否沒有匹配全部元素。
3      * 判斷是否沒有FREE
4      */
5     @Test
6     public void test15 () {
7          boolean b = persons.stream().noneMatch((e) -> Status.FREE.equals(e.getStatus()));
8          System.out.println(b);
9     }

 

 

 

    ④. findFirst —— 返回第一個元素。

 

 1     /**
 2      * findFirst —— 返回第一個元素。
 3      *
 4      */
 5     @Test
 6     public void test16 () {
 7          Optional<Person> person = persons.stream().findFirst();
 8          System.out.println(person);
 9          
10          person.orElse(new Person("王五", "男", 35, Status.BUSY));
11     }

 

  注意:上面findFirst 返回的是一個Optional的對像,他將咱們的Person封裝了一層,這是爲了不空指針。並且這個對象爲咱們提供了一個orElse方法,就是當咱們獲得的這個對象爲空時,咱們能夠傳入一個新得對象去替代它。

 

 

    ⑤. findAny —— 返回當前流中任意元素。

 

 1     /**
 2      * findAny —— 返回當前流中任意元素。
 3      */
 4     @Test
 5     public void test17 () {
 6          Optional<Person> person = persons.stream().findAny();
 7          System.out.println(person);
 8          
 9          person.orElse(new Person("王五", "男", 35, Status.BUSY));
10     }

 

 

 

    ⑥. count —— 返回流中元素總個數。

 

1     /**
2      * count —— 返回流中元素總個數。
3      */
4     @Test
5     public void test18 () {
6          long count = persons.stream().count();
7          System.out.println(count);
8          
9     }

 

 

 

    ⑦. max —— 返回流中最大值。

 

1     /**
2      * max —— 返回流中最大值。
3      */
4     @Test
5     public void test18 () {
6         Optional<Person> person = persons.stream().max((e1, e2) -> Double.compare(e1.getAge(), e2.getAge()));
7          System.out.println(person);
8          
9     }

 

 

 

    ⑧. min —— 返回流中最小值。

 

1     /**
2      * min —— 返回流中最小值。
3      */
4     @Test
5     public void test20 () {
6         Optional<Person> person = persons.stream().min((e1, e2) -> Double.compare(e1.getAge(), e2.getAge()));
7          System.out.println(person);
8          
9     }

 

  2). 歸約(能夠將流中元素反覆結合在一塊兒,獲得一個值)

    ①. reduce(T identitty,BinaryOperator)首先,須要傳一個起始值,而後,傳入的是一個二元運算。

1     /**
2      * reduce(T identitty,BinaryOperator)首先,須要傳一個起始值,而後,傳入的是一個二元運算。
3      */
4     @Test
5     public void test21 () {
6         List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
7         Integer sum = list.stream().reduce(0, (x, y) -> x + y);
8     }

 

    ②. reduce(BinaryOperator)此方法相對於上面方法來講,沒有起始值,則有可能結果爲空,因此返回的值會被封裝到Optional中。

1     /**
2      *  reduce(BinaryOperator)此方法相對於上面方法來講,沒有起始值,則有可能結果爲空,因此返回的值會被封裝到Optional中
3      */
4     @Test
5     public void test22 () {
6         List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
7         Optional<Integer> sum = list.stream().reduce(Integer :: sum);
8     }

 

  備註:map和reduce的鏈接一般稱爲map-reduce模式,因Google用它來進行網絡搜索而出名。

 

  3). 收集collect(將流轉換爲其餘形式。接收一個Collector接口得實現,用於給其餘Stream中元素作彙總的方法)

    Collector接口中方法得實現決定了如何對流執行收集操做(如收集到List,Set,Map)。可是Collectors實用類提供了不少靜態方法,能夠方便地建立常見得收集器實例。

    ①. Collectors.toList() 將流轉換成List

1     /**
2      *  Collectors.toList() 將流轉換成List
3      */
4     @Test
5     public void test23() {
6         7         List<String> names = this.list.stream().map(Person :: getName).collect(Collectors.toList());
8     }

 

    ②. Collectors.toSet()將流轉換爲Set

1     /**
2      *  Collectors.toSet() 將流轉換成Set
3      */
4     @Test
5     public void test24() {
6         7         Set<String> names = this.list.stream().map(Person :: getName).collect(Collectors.toSet());
8     }

 

    ③. Collectors.toCollection()將流轉換爲其餘類型的集合

1     /**
2      *  Collectors.toCollection()將流轉換爲其餘類型的集合
3      */
4     @Test
5     public void test25() {
6         7         LinkedList<String> names =  this.list.stream().map(Person :: getName).collect(Collectors.toCollection(LinkedList :: new));
8     }

    

    ④. Collectors.counting()  元素個數

1     /**
2      *  Collectors.counting()  總數
3      */
4     @Test
5     public void test26() {
6         List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
7         Long count =  list.stream().collect(Collectors.counting());
8     }

 

    ⑤. Collectors.averagingDouble()、Collectors.averagingDouble()、Collectors.averagingLong() 平均數,這三個方法均可以求平均數,不一樣之處在於傳入得參數類型不一樣,返回值都爲Double

 1     /**
 2      *  Collectors.averagingInt() 、
 3      *   Collectors.averagingDouble()、
 4      *    Collectors.averagingLong() 平均數,
 5      *    者三個方法均可以求平均數,不一樣之處在於傳入得參數類型不一樣,
 6      *    返回值都爲Double
 7      */
 8     @Test
 9     public void test27() {
10         List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
11         Double avg =  list.stream().collect(Collectors.averagingInt((x) -> x));
12     }

 

    ⑥. Collectors.summingDouble()、Collectors.summingDouble()、Collectors.summingLong() 求和,不一樣之處在於傳入得參數類型不一樣,返回值爲Integer, Double, Long

 1     /**
 2      *  Collectors.summingInt() 、
 3      *   Collectors.summingDouble()、
 4      *    Collectors.summingLong() 求和,
 5      *    者三個方法均可以求總數,不一樣之處在於傳入得參數類型不一樣,
 6      *    返回值爲Integer, Double, Long
 7      */
 8     @Test
 9     public void test28() {
10         List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
11         Integer sum =  list.stream().collect(Collectors.summingInt((x) -> x));
12     }

 

  ⑦. Collectors.maxBy() 求最大值

1     /**
2      * Collectors.maxBy() 求最大值
3      */
4     @Test
5     public void test29() {
6         List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
7         Optional<Integer> max =  list.stream().collect(Collectors.maxBy((x, y) ->Integer.compare(x, y)));
8     }

 

  ⑧. Collectors.minBy() 求最小值

/**
     * Collectors.minBy() 求最小值
     */
    @Test
    public void test29() {
        List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Optional<Integer> min =  list.stream().collect(Collectors.minBy((x, y) ->Integer.compare(x, y)));
    }

 

  ⑨. Collectors.groupingBy()分組 ,返回一個map

1     /**
2      * Collectors.groupingBy()分組 ,返回一個map
3      */
4     @Test
5     public void test30() {
6         Map<String, List<Person>> personMap =  list.stream().collect(Collectors.groupingBy(Person :: getSex));
7     }

      Collectors.groupingBy()還能夠實現多級分組

1     /**
2      * Collectors.groupingBy()多級分組 ,返回一個map
3      */
4     @Test
5     public void test31() {
6         Map<String, Map<Status, List<Person>>> personMap =  list.stream().collect(Collectors.groupingBy(Person :: getSex, Collectors.groupingBy(Person :: getStatus)));
7     }

 

  ⑩. Collectors.partitioningBy() 分區,參數中傳一個函數,返回true,和false 分紅兩個區

1     /**
2      * Collectors.partitioningBy() 分區,參數中傳一個函數,返回true,和false 分紅兩個區
3      */
4     @Test
5     public void test32() {
6         Map<Boolean, List<Person>> personMap =  list.stream().collect(Collectors.partitioningBy((x) -> x.getAge() > 30));
7     }

 

  上面就是Stream的一些基本操做,只要勤加練習就能夠靈活使用,並且效率大大提升。

相關文章
相關標籤/搜索