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());
使用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映射
首先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。
IntStream.of(1, 2, 3, 4, 5, 6, 7).map(elem -> elem * 10).forEach(System.out::println);
这也就解释了,为什么上面的第二节解决办法里面,用map不行,而需要mapToObj,因为那里做了一个基本类型到包装类型的转化
Java 8之基本类型优化
Java Stream difference between map and mapToObj
How to get element index when using a stream to traverse a list?