參考鏈接: Java 8中迭代帶有索引的流Stream
1. 問題來源?
Java8的Stream流為我們的遍歷集合帶來了方便,基本可以取代for循環了。但是有一些情況需要知道當前遍歷的索引,使用for循環當然可以輕易獲得,但使用stream就很難了。 比如下面這個情況: 有一個集合list,里面存儲的是引用類型。 使用for循環可以輕易的操作索引i?
for (int i = 0; i < list.size(); i++){
? ? System.out.println(list.get(i));
? ? System.out.println(i);
}
?
使用Stream流遍歷list如下,其中handle是一個方法,想在handle方法里面拿到當前索引是很困難的。?
list.stream().map(t -> handle(t)).collect(Collectors.toList());
?
2. 解決辦法?
使用IntStream流來構造一個Int類型的流出來,然后遍歷這個Int的流,list中的對象可以通過get方法來取。具體解決代碼如下:?
IntStream.range(0, lists.size())
? ? ? ? ?.mapToObj(i -> handle(lists.get(i), i))
? ? ? ? ?.collect(Collectors.toList());
?
可以看到代碼里的這一句:handle(lists.get(i), i),這樣就成功的把索引帶入到了handle方法中。?
需要注意的是:在流中必須使用mapToObj,而不能使用map映射?
3. map映射和mapToObj的區別?
首先Stream流下面的類包含了IntStream, LongStream, DoubleStream等?
那么究竟下面兩者有什么區別呢??
Stream<Integer> // 包裝類型
IntStream? ? //基本類型
?
所以對于mapToObj和mapToInt也是同樣的 mapToObj 方法主要是將Stream中的元素進行裝箱操作, 轉換成一個引用類型的值。 mapToInt 方法是將Stream中的 元素轉換成基本類型int。 比如下面的例子?
Stream s = IntStream.of(4, 5, 6).mapToObj(e -> e); //mapToObj method is needed
IntStream is = Stream.of(4, 5, 6).mapToInt(e -> e); //mapToInt method is needed
?
可以看到Stream是包裝類型,所以想要把IntStream基本類型流轉化成包裝類型,就需要使用mapToObj。?
上面兩個mapToObj和mapToInt是進行類型的轉化,那么map的作用呢? map不進行類型轉化,如果原來流中是基本類型,map映射完應當還是基本類型,如果原來是包裝類型,映射完應當還是包裝類型。 比如下面這個例子:?
IntStream.of(1, 2, 3, 4, 5, 6, 7).map(elem -> elem * 10).forEach(System.out::println);
?
這也就解釋了,為什么上面的第二節解決辦法里面,用map不行,而需要mapToObj,因為那里做了一個基本類型到包裝類型的轉化?
3. 總結?
使用IntStream可以靈活的操作對象和獲取索引。map不進行包裝和基本類型的轉化,mapToObj是基本轉為包裝,mapToInt是包裝轉為基本。?
END?
參考?
Java 8之基本類型優化 Java Stream difference between map and mapToObj How to get element index when using a stream to traverse a list?