本文图解了Java8 Stream的几个常用方法:forEach(), map(), filter(), sorted()。
Stream流是Java8新增的一个特性,可以让你以声明的方式处理数据,像SQL语句一样,对数据进行筛选、排序和聚合等操作,而不对源数据进行更改。
Stream API可以简洁我们的代码,大大提升可读性。 咱们先看几个方法感受一下。
Stream.forEach()
看方法名,大概能猜出来,是对流进行遍历。其方法签名void forEach(Consumer<? super E> action)
,作用是对容器中的每个元素执行action指定的动作。
public static void main(String[] args) {
List<User> userList = getUserList();
// userId=1
// userId=2
// userId=3
userList.forEach(e -> System.out.println("userId=" + e.getUserId()));
}
private static List<User> getUserList() {
return Arrays.asList(new User().setUserId(1),
new User().setUserId(2),
new User().setUserId(3));
}
Stream.map()
可以理解为是一个转换函数,对每个元素按照某种操作进行转换。
Java8之前
List<User> userList = getUserList();
List<UserVO> userVOList = new ArrayList<>();
for (User user : userList) {
UserVO userVO = new UserVO();
userVO.setUserId(user.getUserId());
// 省略set方法
userVOList.add(userVO);
}
使用Java8 Stream
List<User> userList = getUserList();
List<UserVO> userVOList = userList.stream().map(user -> {
UserVO userVO = new UserVO();
userVO.setUserId(user.getUserId());
// 省略set方法
return userVO;
}).collect(Collectors.toList());
.stream()
将一个集合转换为Stream流.collect()
用于结果的收集- Collectors 收集器将流转换成集合和聚合元素
与Java8之前的区别在于,省略了new ArrayList<>()的过程,使用map函数,将User映射为UserVO。
Stream.filter()
函数的签名为 Streampredicate
条件元素的Stream。也就是说filter是一个过滤函数。
这里要解释一下predicate
,其中文意思是谓语,是一个布尔值函数,可以理解为条件。
比如需要获取集合中userId为奇数的集合:
List<User> userList = getUserList();
userList.stream()
.filter(user -> user.getUserId() % 2 == 1)
.forEach(user -> System.out.println("userId=" + user.getUserId()));
// 控制台输出
// userId=1
// userId=3
Stream.sorted()
sorted的作用是对流中的元素进行排序排序,它有两个方法签名:Stream
比如把集合按照userId倒序排序:
private static List<User> getUserList() {
return Arrays.asList(new User().setUserId(1),
new User().setUserId(3),
new User().setUserId(2));
}
public static void main(String[] args) {
// User没有实现Comparable接口
List<User> userList = getUserList();
userList.stream()
// Exception in thread "main" java.lang.ClassCastException:
// User cannot be cast to java.lang.Comparable
.sorted()
.forEach(user -> System.out.println("userId=" + user.getUserId()));
}
public static void main(String[] args) {
List<User> userList = getUserList();
userList.stream()
.sorted((u1, u2) -> u2.getUserId() - u1.getUserId())
.forEach(user -> System.out.println("userId=" + user.getUserId()));
}
// 控制台输出
// userId=3
// userId=2
// userId=1
小结
细心的同学可能会发现,forEach()没有返回值,而map(), filter(), sorted()的返回值还是一个Stream。实际上,对Stream的操作分为为两类:
- 中间操作(intermediate operations):总是会惰式执行
- 结束操作(terminal operations):会触发实际计算
可以这么理解,返回值为Stream的,都是中间操作,那什么是惰式执行呢?就是说中间操作是不会立即执行的,直到遇到结束操作,才会执行。比如下面一段代码是不会执行的:
Stream.of("a", "b", "c", "d", "e")
.filter(s -> {
System.out.println("filter: " + s);
return true;
});
这样的话,我们可以通过多个中间操作 + 1个结束操作,对数据进行筛选、排序、转换和收集等操作。
那这多个中间操作的顺序有什么讲究吗?可以留言谈谈你的观点。