手把手帶你體驗Stream流

前言

只有光頭才能變強。java

文本已收錄至個人GitHub倉庫,歡迎Star:github.com/ZhongFuChen…git

上一篇講解到了Lambda表達式的使用《最近學到的Lambda表達式基礎知識》,還沒看的同窗能夠先去閱讀一下哈~github

相信也有很多的同窗想要知道:Lambda表達式在工做中哪一個場景會用得比較多?跟Lambda搭邊的,使用Stream流會比較多編程

通常人第一次看Stream流的代碼,都會有點看不懂(它的代碼看起來好像就不是寫Java同樣.),但願這篇文章能帶你們入個門數組

1、體驗Stream流

你們在自學時,大多數會學過一個程序:算出從數組元素的和,當時咱們是怎麼寫的?通常來講是這樣的:併發

public static void main(String[] args) {
    int[] nums = { 1, 2, 3 };
    int sum = 0;
    for (int i : nums) {
        sum += i;
    }
    System.out.println("結果爲:" + sum);
}
複製代碼

若是咱們使用Stream流的話,能夠這樣:dom

public static void main(String[] args) {
    int[] nums = { 1, 2, 3 };
    int sum2 = IntStream.of(nums).sum();
    System.out.println("結果爲:" + sum2);
}
複製代碼

代碼量上能夠明顯看出,用Stream流的方式會少一些。性能

我理解的Stream流編程就是:某些場景會常常用到操做(求和/去重/過濾....等等),已經封裝好API給你了,你本身別寫了,調我給你提供的API就行了測試

1.1 支持併發

回到咱們最原始的代碼:優化

public static void main(String[] args) {
    int[] nums = { 1, 2, 3 };
    int sum = 0;
    for (int i : nums) {
        sum += i;
    }
    System.out.println("結果爲:" + sum);
}
複製代碼

若是咱們想要for循環的內部支持併發的話,顯然不太好去寫。但使用Stream流的方式,調用一個方法就能夠支持併發(parallel):

public static void main(String[] args) {
    int[] nums = { 1, 2, 3 };
    int sum2 = IntStream.of(nums).parallel().sum();
    System.out.println("結果爲:" + sum2);
}
複製代碼

優勢:調API確定是比本身寫的代碼量要少。

缺點:不太方便調試

爲何要使用Stream流在我看來就是以上兩個緣由:

  • 方便併發
  • 代碼量少(直接調用API)

2、如何使用Stream流?

Stream繼承結構圖

使用Stream流分爲三步:

  1. 建立Stream流
  2. 經過Stream流對象執行中間操做
  3. 執行最終操做,獲得結果

三步走

2.1 建立流

建立流咱們最經常使用的就是從集合中建立出流

/** * 返回的都是流對象 * @param args */
public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    // 從集合建立
    Stream<String> stream = list.stream();
    Stream<String> stream1 = list.parallelStream();

    // 從數組建立
    IntStream stream2 = Arrays.stream(new int[]{2, 3, 5});

    // 建立數字流
    IntStream intStream = IntStream.of(1, 2, 3);

    // 使用random建立
    IntStream limit = new Random().ints().limit(10);

}
複製代碼

2.2 執行中間操做

怎麼理解中間操做?意思是這樣的:在上面咱們已經能建立出Stream了,咱們是對Stream進行操做,對Stream操做返回完返回的仍是Stream,那麼咱們稱這個操做爲中間操做。

中間操做 解釋

好比,咱們如今有個字符串my name is 007,代碼以下:

String str = "my name is 007";

Stream.of(str.split(" ")).filter(s -> s.length() > 2)
    .map(s -> s.length()).forEach(System.out::println);
複製代碼

分解:

一、從字符串數組建立出流對象:

Stream<String> split = Stream.of(str.split(" "));
複製代碼

二、經過流對象的API執行中間操做(filter),返回的仍是流對象:

Stream<String> filterStream = split.filter(s -> s.length() > 2);
複製代碼

三、經過返回的流對象再執行中間操做(map),返回的仍是流對象:

Stream<Integer> integerStream = filterStream.map(s -> s.length());
複製代碼

由於中間操做返回的都是流對象,因此咱們能夠鏈式調用

注意:Stream上的操做並不會當即執行,只有等到用戶真正須要結果的時候纔會執行(惰性求值)。

好比說,peek()是一箇中間操做,返回的是Stream流對象,只要它不執行最終的操做,這個Stream是不會執行的。

String str = "my name is 007";
Stream.of(str.split(" ")).peek(System.out::println); // 不會有信息打印
複製代碼

2.3 執行最終操做

最終操做返回的再也不是Stream對象,調用了最終操做的方法,Stream纔會執行。仍是以上面的例子爲例:

String str = "my name is 007";
Stream.of(str.split(" ")).peek(System.out::println).forEach(System.out::println)
複製代碼

此次咱們加入了最終操做,因此此次的Stream流會被執行,因爲中間操做和最終操做都是執行打印,因此會看到兩次打印:

結果圖

至於中間操做和最終操做怎麼區分,咱們以返回值來看就好了。中間操做返回的是Stream實例對象,最終操做返回的不是Stream實例對象:

Stream接口的方法

最後

這篇文章主要跟你們一塊兒初步認識一下Stream流,至於中間操做、最終操做的API講解我就不寫了(網上的教程也不少)

使用Stream的緣由我認爲有兩個:

  1. JDK庫提供現有的API,代碼寫起來簡潔優化
  2. 方便併發。你們能夠記住一個結論:在多核狀況下,可使用並行Stream API來發揮多核優點。在單核的狀況下,咱們本身寫的for性能不比Stream API 差多少

參考資料:

樂於輸出乾貨的Java技術公衆號:Java3y。公衆號內有200多篇原創技術文章、海量視頻資源、精美腦圖,關注便可獲取!

轉發到朋友圈是對我最大的支持!

以爲個人文章寫得不錯,點

相關文章
相關標籤/搜索