1. 程式人生 > 其它 >java 8 Stream中操作型別和peek的使用

java 8 Stream中操作型別和peek的使用

java 8 Stream中操作型別和peek的使用

簡介

java 8 stream作為流式操作有兩種操作型別,中間操作和終止操作。這兩種有什麼區別呢?

我們看一個peek的例子:

Stream<String> stream = Stream.of("one", "two", "three","four");
        stream.peek(System.out::println);

上面的例子中,我們的本意是打印出Stream的值,但實際上沒有任何輸出。

為什麼呢?

中間操作和終止操作

一個java 8的stream是由三部分組成的。資料來源,零個或一個或多箇中間操作,一個或零個終止操作。

中間操作是對資料的加工,注意,中間操作是lazy操作,並不會立馬啟動,需要等待終止操作才會執行。

終止操作是stream的啟動操作,只有加上終止操作,stream才會真正的開始執行。

所以,問題解決了,peek是一箇中間操作,所以上面的例子沒有任何輸出。

peek

我們看下peek的文件說明:peek主要被用在debug用途。

我們看下debug用途的使用:

Stream.of("one", "two", "three","four").filter(e -> e.length() > 3)
                .peek(e -> System.out.println("Filtered value: " + e))
                .map(String::toUpperCase)
                .peek(e -> System.out.println("Mapped value: " + e))
                .collect(Collectors.toList());

上面的例子輸出:

Filtered value: three
Mapped value: THREE
Filtered value: four
Mapped value: FOUR

上面的例子我們輸出了stream的中間值,方便我們的除錯。

為什麼只作為debug使用呢?我們再看一個例子:

Stream.of("one", "two", "three","four").peek(u -> u.toUpperCase())
                .forEach(System.out::println);

上面的例子我們使用peek將element轉換成為upper case。然後輸出:

one
two
three
four

可以看到stream中的元素並沒有被轉換成大寫格式。

再看一個map的對比:

Stream.of("one", "two", "three","four").map(u -> u.toUpperCase())
                .forEach(System.out::println);

輸出:

ONE
TWO
THREE
FOUR

可以看到map是真正的對元素進行了轉換。

當然peek也有例外,假如我們Stream裡面是一個物件會怎麼樣?

    @Data
    @AllArgsConstructor
    static class User{
        private String name;
    }
        List<User> userList=Stream.of(new User("a"),new User("b"),new User("c")).peek(u->u.setName("kkk")).collect(Collectors.toList());
        log.info("{}",userList);

輸出結果:

10:25:59.784 [main] INFO com.flydean.PeekUsage - [PeekUsage.User(name=kkk), PeekUsage.User(name=kkk), PeekUsage.User(name=kkk)]

我們看到如果是物件的話,實際的結果會被改變。

為什麼peek和map有這樣的區別呢?

我們看下peek和map的定義:

Stream<T> peek(Consumer<? super T> action)
<R> Stream<R> map(Function<? super T, ? extends R> mapper);

peek接收一個Consumer,而map接收一個Function。

Consumer是沒有返回值的,它只是對Stream中的元素進行某些操作,但是操作之後的資料並不返回到Stream中,所以Stream中的元素還是原來的元素。

而Function是有返回值的,這意味著對於Stream的元素的所有操作都會作為新的結果返回到Stream中。

這就是為什麼peek String不會發生變化而peek Object會發送變化的原因。

結論

我們在本文中講解了stream的兩個操作型別,並總結了peek的使用。希望大家能夠掌握。

本文的例子https://github.com/ddean2009/learn-java-streams/tree/master/stream-peek