Java8的Stream流为我们的遍历集合带来了方便,基本可以取代for循环了。但是有一些情况需要知道当前遍历的索引,使用for循环当然可以轻易获得,但使用stream就很难了。但是并不是没有办法的事,如下所示
一,代码示例
1)Lambda.class
package com.example.demo.main;
import com.example.demo.Bean.Food;
import com.example.demo.Bean.User;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Lambda {
public static void main(String[] args) {
IntStream.of(7, 2, 3, 4, 5, 6, 9).map(elem -> elem * 10).forEach(System.out::println);
List users = new ArrayList<>();
User user = new User(5L, "name5", new Food(5L, "food1", 5));
User user2 = new User(3L, "name3", new Food(3L, "food2", 3));
User user3 = new User(4L, "name4", new Food(4L, "food3", 4));
User user4 = new User(9L, "name9", new Food(9L, "food4", 9));
User user5 = new User(7L, "name7", new Food(7L, "food5", 7));
users.add(user);
users.add(user2);
users.add(user3);
users.add(user4);
users.add(user5);
// 首先根据user的id进行排序
List sortedUsers = users.stream()
.sorted(Comparator.comparingLong(User::getId))
.collect(Collectors.toList());
// 然后将排序后的user的Food的num的值改为排序后的索引位置赋值
// 使用IntStream流来构造一个Int类型的流出来,然后遍历这个Int的流,list中的对象可以通过get方法来取。其中modifyFoodNum(sortedUsers.get(i),i)成功的将索引带到了方法中
// 需要注意的是:在流中必须使用mapToObj,而不能使用map映射,也不能省去collect(...)方法
IntStream.range(0, sortedUsers.size()).mapToObj(i -> modifyFoodNum(sortedUsers.get(i), i)).collect(Collectors.toList());
sortedUsers.stream().forEach(System.out::println);
}
public static User modifyFoodNum(User user, int i) {
Food food = user.getFood();
System.out.println("i的当前值为:" + i);
food.setNum(i + 1);
return user;
}
}
2) Food类:
package com.example.demo.Bean;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class Food {
private Long id;
private String name;
private Integer num;
public Food(Long id, String name, Integer num) {
this.id = id;
this.name = name;
this.num = num;
}
@Override
public String toString() {
return "Food{" +
"id=" + id +
", name='" + name + '\'' +
", num=" + num +
'}';
}
}
3)User类:
package com.example.demo.Bean;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class User {
private Long id;
private String name;
private Food food;
public User(Long id, String name, Food food) {
this.id = id;
this.name = name;
this.food = food;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", food=" + food +
'}';
}
}
二,map映射和mapToObj的区别
首先Stream流下面的类包含了IntStream, LongStream, DoubleStream等
Stream // 包装类型
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(7, 2, 3, 4, 5, 6, 9).map(elem -> elem * 10).forEach(System.out::println);
这也就解释了,为什么上面的第二节解决办法里面,用map不行,而需要mapToObj,因为那里做了一个基本类型到包装类型的转化
三. 总结
参考:https://www.jianshu.com/p/183b3d1c30a2