流(Stream)是Java8的新特性,它允许你以声明式的方式处理数据集合,可以把它看作是遍历数据集的高级迭代器。
假如我们要对一些用户进行筛选,找出年龄大于25岁的人,按照身高排序,再获得他们的姓名,在Java8之前,我们的代码是:
List<User> users = new ArrayList();
...
// 筛选
List<User> filterResult = new ArrayList();
for (User user : users) {
if (user.getAge() > 25){
filterResult.add(user)
}
}
// 排序
filterResult.sort(new Connparator<User>() {
public int compare(User user1, User user2)(
return user1.getHeight().compareTo(user2.getHeight());
)
}
// 取值转换list
List<String> result = new ArrayList();
for (User user : filterResult) {
result.add(apple.getName);
}
在上面的代码中,用到了filterResult
这个中间变量,而他唯一的作用就是作为一次性的容器,而Java8中,可以使用另一种写法:
List<User> users = new ArrayList();
...
List result = users.stream()
.filter(e -> e.getAge > 25) // 筛选
.sorted(comparing(User::getHeight)) // 排序
.map(e -> e.getName) // 取值转换list
.collect(Collectors.toList);
这里使用的就是Java8中的stream
流,使用的是声明性方式写的:说明想要完成什么(筛选,排序,取值),而不说明如何实现一个操作(for 循环)。同时可以将这些操作链接起来,达到一种流水线式
的效果:
Java8中的集合支持一个新的Stream
方法,它会返回一个流
。什么是流呢?简单的定义,就是“从支持数据处理操作的源生成的元素序列”:
简单来说,我们通过一个集合的stream方法获取一个流,然后对流进行一系列流操作(操作之间数据依然以流的形式存在),最后再构建成我们需要的数据集合。
流操作可以分为两类:中间操作和终端操作。回看之前的代码:
List result = users.stream() // 获得流
.filter(e -> e.getAge > 25) // 中间操作
.sorted(comparing(User::getHeight)) // 中间操作
.map(e -> e.getName) // 中间操作
.collect(Collectors.toList); // 终端操作
简化一下就是:
? 数据源 => 中间操作 => 终端操作 => 结果
诸如filter或者sort等中间操作会返回另一个流,进而进行下一步流操作,而终端操作则是将流关闭,构建新的数据集合对象(也可以不构建)。
这一系列的流操作构建了一个流水,但是,必须要在流水上存在一个终端操作,否则中间操作都不会执行,所有的中间操作会在终端操作时一次性处理完成。
常用的流操作有:
流操作 | 作用 |
---|---|
filter | 过滤 |
map | 映射替换 |
distinct | 去重 |
sorted | 按照比较器Comparator排序 |
limit | 截取 |
skip | 跳过 |
流操作 | 作用 |
---|---|
foreach | 对流中元素遍历操作 |
toArray | 将流中元素倒入一个数组 |
collect | 将流中的元素倒入某些容器中,比如Collection或者Map |
min | 按照比较器Comparator找出流中最小值 |
max | 按照比较器Comparator找出流中最大值 |
count | 计算流中元素数量 |
anyMatch | 判断是否存在一个匹配结果,短路操作 |
allMatch | 判断是否全部匹配,短路操作 |
findAny | 查找任何一个匹配的结果,短路操作 |
Reduce | 所有元素求和 |
以下总结了一些开发中接触到的一些流的简单应用:
// area 按照 code 和 name 构建map
List<Area> areaList = new ArrayList();
...
Map<String, String> areaCodeNameMap = areaList.stream().collect(Collectors.toMap(Area::getCode, Area::getName));
// area 按照 code 归类 成map
List<Area> areaList = new ArrayList();
...
Map<String, List<Area>> bigAreaCodeMap = areaList.stream().collect(Collectors.groupingBy(Area::getCode));
List<User> list = new ArrayList();
...
// 自然排序
list.stream().sorted().collect(Collectors.toList())
// 自然逆序
list.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList())
// 使用比较器排序
list.stream().sorted(Comparator.comparing(User::getAge)).collect(Collectors.toList())
// 使用比较器逆序
list.stream().sorted(Comparator.comparing(User::getAge).reversed()).collect(Collectors.toList())
List uniqueList = list.stream().distinct().collect(Collectors.toList());
// 判断是否所有的卡路里都小于1000
boolean isHealthy = menu.stream().allMatch(e -> e.getCalories() < 1000);
// 查找第一个
List<Integer> someNumbers = Arrays.asList(1,2,3,4,5);
Optional<Integer> firstSquareDivisibleByTree = someNumbers.stream()
.map(x -> x * x)
.filter(x -> x % 3 == 0)
.findFirst();
// findFirst 返回的是一个Optional对象, 需要get()方法获得目标值
Integer num = firstSquareDivisibleByTree.get();
// 有初始值
int sum = numbers.stream().reduce(0, (a, b) -> a + b)
// 没初始值
Optional<Integer> = numbers.stream().reduce((a, b) -> a + b));
// 最大值
int maxNum = numbers.stream().reduce(Integer::max).get()
// 计数
int count = numbers.stream().filter(e -> e > 3).count()
原文:https://www.cnblogs.com/wxlzzz/p/11421604.html