Stream接口的使用

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

相關文章
相關標籤/搜索