IntStream.of(1, 2, 3, 4, 5, 6).forEach(System.out::println);
這個直接使用集合的forEach也是能夠的,使用stream除了有原始類型版本減小拆包裝包之外,還能夠實現並行化:java
IntStream.of(1, 2, 3, 4, 5, 6).parallel().forEach(System.out::println); System.out.println(); IntStream.of(1, 2, 3, 4, 5, 6).parallel().forEach(System.out::println);
輸出:
4
5
1
2
6
3
4
1
6
2
3
5
可見,使用了多線程並行處理stream,每一個元素被調用的順序是不肯定的。stream還提供了一個順序的forEachOrdered,對於串行stream來講,這個方法和forEach相同,而對於並行
stream則會強制按順序執行,如:
多線程
IntStream.of(1, 2, 3, 4, 5, 6).parallel().forEachOrdered(System.out::println);
輸出:
1
2
3
4
5
6
一樣的道理,findFirst和findAny對於串行steam來講是同樣的,而對於並行stream則不一樣:ide
System.out.println(Stream.of(1, 2, 3, 4, 5, 6).findFirst()); System.out.println(Stream.of(1, 2, 3, 4, 5, 6).findAny());
輸出
Optional[1]
Optional[1]
再試下並行stream:測試
System.out.println(Stream.of(1, 2, 3, 4, 5, 6).parallel().findFirst()); System.out.println(Stream.of(1, 2, 3, 4, 5, 6).parallel().findAny()); System.out.println(Stream.of(1, 2, 3, 4, 5, 6).parallel().findAny()); System.out.println(Stream.of(1, 2, 3, 4, 5, 6).parallel().findAny());
輸出
Optional[1]
Optional[4]
Optional[4]
Optional[2]spa
findFirst和findAny返回一個Optional<T>(對於原始類型stream,是返回OptionalInt,
OptionalLong,OptionalDouble), 由於對於空的stream,這兩個方法須要返回一個找不到元素的語義(有別於null),獲得Optional後能夠用isPresent判斷元素是否存 在,用get方法得到真正的值(若是元素不存在,調用get方法會拋出NoSuchElementException)。不過這個Optional有些坑 爹:
Stream.of(null,1,2,3).findFirst();
執行結果是拋出java.lang.NullPointerException,緣由是Optional構造時不容許傳入null,這裏我沒明白既然Optional用來區別null和present的語義,爲何又不能傳入null。
findFirst和findAny和filter方法配合能夠實現得到知足條件的第一個元素(或者任意一個元素),例如咱們要找第一個負數,能夠這麼寫:線程
stream.filter(x -> x < 0).findFirst();code
接着測試Stream的惰性加載特性:排序
List<Integer> list = new AbstractList<Integer>() { @Override public Integer get(int index) { System.out.println(index); return index; } @Override public int size() { return 3; } }; Stream<Integer> stream = list.stream(); System.out.println("get stream"); stream.forEach(System.out::println);
輸出:
get stream
0
0
1
1
2
2
可見構造stream的時候 並不會訪問List中的元素,等調用消費方法的時候,真正須要使用到某個元素再去訪問。與iterator不一樣的是,構造iterator以後,若是 list被修改,再使用stream,並不會拋出ConcurrentModificationException,例如:get
List<Integer> list = new ArrayList<>(); list.add(1); list.add(2); Stream<Integer> stream = list.stream(); list.add(3); stream.forEach(System.out::println);
輸出:
1
2
3it
同理,測試映射方法的惰性加載特性:
List<Integer> list = new AbstractList<Integer>() { @Override public Integer get(int index) { System.out.println(index); return index; } @Override public int size() { return 3; } }; Stream<Integer> stream = list.stream().map(x -> { System.out.println(x); return x * 2; }); System.out.println("get stream"); stream.forEach(x -> { System.out.println(x); System.out.println(); });
輸出:
get stream
0
0
0
1
1
2
2
2
4
對於不須要讀到的元素,則連加載都不會加載:
List<Integer> list = new AbstractList<Integer>() { @Override public Integer get(int index) { System.out.println(index); return index; } @Override public int size() { return 3; } }; Stream<Integer> stream = list.stream().limit(1); System.out.println("get stream"); stream.forEach(System.out::println);
輸出:
get stream
0
0
可見,只會去加載第一個元素。
也能夠用peek方法來監控stream中元素的讀取:
Stream.of(1, 2, 3, 4).peek(x -> System.out.print(x + " ")).map(x -> x * 2) .forEach(System.out::println);
輸出:
1 2
2 4
3 6
4 8
對於sorted方法,狀況和其它映射方法略有不一樣:
Stream<Integer> stream = Stream.of(3, 1, 2, 4) .peek(System.out::println).sorted(); System.out.println("get sorted stream"); stream.forEach(x -> System.out.println(" " + x));
輸出:get sorted stream3124 1 2 3 4從輸出結果能夠看出,雖然是開始消費sorted stream的時候纔會去訪問原stream中的元素,不過在消費一開始的時候,全部元素就被遍歷一遍了,這是由於只有把全部元素取出來才能排序,會消耗一個O(n)的額外空間。測試Stream的一次性特性: IntStream stream = IntStream.of(1, 2, 3, 4 - 1, 5); System.out.println(stream.sum()); System.out.println(stream.anyMatch(x -> x < 0));調用anyMatch的時候拋出異常:java.lang.IllegalStateException: stream has already been operated upon or closed調用映射方法後,原來的stream再也不可用,如: IntStream stream = IntStream.of(1, 2, 3, 4 - 1, 5); stream.limit(1); System.out.println(stream.sum());拋出異常:java.lang.IllegalStateException: stream has already been operated upon or closed源stream關閉後,用映射方法構造出來的stream也再也不可用。 IntStream stream = IntStream.of(1, 2, 3, 4 - 1, 5); IntStream limit = stream.limit(1); stream.close(); System.out.println(limit.sum());拋出異常:java.lang.IllegalStateException: source already consumed or closed固然,通常咱們使用stream的時候都是鏈式調用,不會犯上面的錯誤。一個stream被close後,相關的stream都會被close Stream.of(1, 2, 3, 4, 5, 6).onClose(() -> System.out.println("close1")) .limit(1).onClose(() -> System.out.println("close2")).close();輸出:close1close2 Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6); stream.onClose(() -> System.out.println("close1")).limit(1) .onClose(() -> System.out.println("close2")); stream.close();輸出:close1close2