Java8新特性學習-Stream

Java8新特性學習-Stream😝

介紹

Java 8 新增了一個新的抽象稱爲流Stream,我的感受這個超級好用,尤爲是業務開發,常常須要對數據列表進行處理的時候,用更少的代碼、更優雅地實現功能。html

這個流式操做,更像是Linux中的管道命令'|',上一個操做的結果傳送到下一個流程中繼續處理,例如:java

+--------------------+       +------+   +------+   +---+   +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+       +------+   +------+   +---+   +-------+
複製代碼

在java代碼實現linux

String content = "hello,world,debug,the,world";
        List<String> list = Arrays.asList(content.split(","));

                List<String> filter = list.stream()
                .filter(temp -> temp.startsWith("w"))
                .map(temp -> temp.substring(0, 3))
                .collect(Collectors.toList());

        filter.forEach(System.out::print);
複製代碼

什麼是Stream

Stream(流)是一個來自數據源的元素隊列並支持聚合操做git

  • 元素是特定類型的對象,造成一個隊列。Java中的Stream並不會存儲元素,而是按需計算。
  • 數據源 流的來源能夠是集合、數組、I/O Channel等
  • 聚合操做 相似SQL語句,好比filter、map、reduce、find、match、sorted等

和之前的Collection操做不一樣,Stream還有兩個基礎特徵:github

  • Pipelining:中間操做都會返回流對象自己。這樣多個操做能夠串聯成一個管道。
  • 內部迭代:之前對集合遍歷都是經過Iterator或者For-Each的方式,顯示的在集合外部進行迭代。Stream提供了內部迭代的方式,經過訪問者模式(Visitor)實現。

生成流

在Java8中,集合接口有兩個方法生成流:數組

  • stream() : 爲集合建立串行流。
  • parallelStream() - 爲集合建立並行流。

這裏要講一下這二者的區別:多線程

通俗點來講,一個是單線程、另外一個是多線程。parallelStream是一個並行執行的流,經過默認的ForkJoinPool,能夠提升多線程任務的速度。處理的過程會分而質之,將一個大任務切分紅多個小任務,而後將結果合起來。(固然這也是一把雙刃劍,在多線程的狀況下,數據的併發訪問須要關注,這也能夠好好學一下,等以後再看吧~)併發


forEach

之前都是顯示的使用循環,例如對一個集合進行打印: JDK7之前ide

for (int i = 0; i < list.size(); i++) {
    String temp = list.get(i);
    System.out.print(temp);
}

// 或者語法糖形式
for (String temp : list) {
    System.out.print(temp);
}
複製代碼

JDK8以後函數

list.forEach(System.out::println);
複製代碼

對比一下,發現只須要一行代碼就能實現~ 若是想在forEach中進行自定義的操做,能夠建立一個類,實現Consumer函數接口,傳遞進去使用~


map

map方法用於映射每一個元素到對應的結果:

Car car1 = Car.create(Car::new, "小汽車1");
        Car car2 = Car.create(Car::new, "小汽車2");
        List<Car> carList = Lists.newArrayList(car1, car2);

        List<String> nameList = carList.stream().map(Car::getName).collect(Collectors.toList());
        // 還能夠加入filter功能,先進行過濾,而後取出想要的字段組成新的列表
複製代碼

Car類:

public class Car {
    
    private Integer id;

    private String name;

    public static Car create(final Supplier<Car> supplier, String name) {
        Car car = supplier.get();
        car.setName(name);
        return car;
    }

    public static void collide(final Car car) {
        System.out.println("Collided " + car.toString());
    }

    public void follow(final Car another) {
        System.out.println("Following the " + another.toString());
    }

    public void repair() {
        System.out.println("Repaired " + this.toString());
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Car{}" + Thread.currentThread().getId() + getName();
    }
}

複製代碼

filter

如其名,filter就是用來過濾的,根據特定的條件來過濾元素:

List<Integer> ints = Lists.newArrayList(1, 5, 6, 7, 10, 20, 31, 8, 9);

        long count = ints.stream().filter(number -> number > 10).count();
        System.out.println(count);

複製代碼

上面的例子是用來過濾出整數列表中,值大於10的數量。


limit

用來獲取指定數量的流(相似於MySQL中的limit):

public void limitTest() {
        List<Integer> ints = Lists.newArrayList(1, 5, 6, 7, 10, 20, 31, 8, 9);
        ints.stream().limit(5).forEach(System.out::println);
    }
複製代碼

sorted

用來對流進行排序,相似於Collections.sort(list, Comparator);

List<Integer> ints = Lists.newArrayList(1, 5, 6, 7, 10, 20, 31, 8, 9);
        ints.sort(Comparator.naturalOrder());

        Car car1 = Car.create(Car::new, "小汽車1");
        Car car2 = Car.create(Car::new, "小汽車2");
        List<Car> carList = Lists.newArrayList(car1, car2);
        // 能夠自定義排序的字段,若是須要更復雜的排序規則,能夠在lambda中的statement進行編寫
        carList.sort(Comparator.comparing(Car::getName));
複製代碼

Collectors

Collectors類實現了不少規約操做,例如將流轉換成集合和聚合元素。(通常用Collectors.toList()就夠了)

//例如在一組對象中或者主鍵ID的列表能夠這樣寫
public void collectorsTest() {
        List<Car> carList = Lists.newArrayList();
        // 省略構建參數,獲取列表中的主鍵ID列表
        List<Integer> ids = carList.stream().map(Car::getId).collect(Collectors.toList());
    }

複製代碼

統計statistics

這個功能比較少用,仍是學習記錄一下吧。

public void statisticsTest() {
        List<Integer> ints = Lists.newArrayList(1, 5, 6, 7, 10, 20, 31, 8, 9);
        IntSummaryStatistics statistics = ints.parallelStream().mapToInt(x -> (int) x).summaryStatistics();
        System.out.println("最大值 : " + statistics.getMax());
        System.out.println("最小值 :" + statistics.getMin());
        System.out.println("平均值 :" + statistics.getAverage());
        System.out.println("總和 : " + statistics.getSum());
        System.out.println("數量 :" + statistics.getCount());
    }
複製代碼

完整的測試代碼

package com.example.demo;

import com.example.demo.test.Car;
import com.google.common.collect.Lists;
import org.junit.Test;

import java.util.Arrays;
import java.util.Comparator;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.stream.Collectors;

/** * @author JingQ at 2019/1/31 */
public class JDK8StreamTest {

    @Test
    public void buildStreamTest() {
        String content = "hello,world,debug,the,world";
        List<String> list = Arrays.asList(content.split(","));

        List<String> filter = list.stream()
                .filter(temp -> temp.startsWith("w"))
                .map(temp -> temp.substring(0, 3))
                .collect(Collectors.toList());
        filter.forEach(System.out::print);
    }

    @Test
    public void forEachTest() {
        String content = "hello,world,debug,the,world";
        List<String> list = Arrays.asList(content.split(","));

        list.forEach(System.out::println);
    }


    @Test
    public void mapTest() {

        Car car1 = Car.create(Car::new, "小汽車1");
        Car car2 = Car.create(Car::new, "小汽車2");
        List<Car> carList = Lists.newArrayList(car1, car2);

        List<String> nameList = carList.stream().map(Car::getName).collect(Collectors.toList());
        // 還能夠加入filter功能,先進行過濾,而後取出想要的字段組成新的列表
    }

    /** * filter過濾 */
    @Test
    public void filterTest() {
        List<Integer> ints = Lists.newArrayList(1, 5, 6, 7, 10, 20, 31, 8, 9);

        long count = ints.stream().filter(number -> number > 10).count();
        System.out.println(count);
    }

    /** * limit 限制數量 */
    @Test
    public void limitTest() {
        List<Integer> ints = Lists.newArrayList(1, 5, 6, 7, 10, 20, 31, 8, 9);
        ints.stream().limit(5).forEach(System.out::println);
    }

    @Test
    public void sortedTest() {
        List<Integer> ints = Lists.newArrayList(1, 5, 6, 7, 10, 20, 31, 8, 9);
        ints.sort(Comparator.naturalOrder());

        Car car1 = Car.create(Car::new, "小汽車1");
        Car car2 = Car.create(Car::new, "小汽車2");
        List<Car> carList = Lists.newArrayList(car1, car2);
        // 能夠自定義排序的字段,若是須要更復雜的排序規則,能夠在lambda中的statement進行編寫
        carList.sort(Comparator.comparing(Car::getName));
    }

    @Test
    public void collectorsTest() {
        List<Car> carList = Lists.newArrayList();
        // 省略構建參數,獲取列表中的主鍵ID列表
        List<Integer> ids = carList.stream().map(Car::getId).collect(Collectors.toList());
    }

    @Test
    public void statisticsTest() {
        List<Integer> ints = Lists.newArrayList(1, 5, 6, 7, 10, 20, 31, 8, 9);
        IntSummaryStatistics statistics = ints.parallelStream().mapToInt(x -> (int) x).summaryStatistics();
        System.out.println("最大值 : " + statistics.getMax());
        System.out.println("最小值 :" + statistics.getMin());
        System.out.println("平均值 :" + statistics.getAverage());
        System.out.println("總和 : " + statistics.getSum());
        System.out.println("數量 :" + statistics.getCount());
    }
}


複製代碼

小結

JDK的流式處理真的是太方便了(雖然之前的代碼能夠顯示的調用,但感受使用更少的代碼來實現更加優雅😁)


我的博客項目地址

但願各位幫忙點個star,給我加個小星星✨


參考資料

一、Java 8 Stream

相關文章
相關標籤/搜索