Java8学习笔记——Stream

流是什么

流(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 循环)。同时可以将这些操作链接起来,达到一种流水线式的效果:

graph LR A[users] --> o1((流)) o1 --> B(filter) B --> o2((流)) o2 --> C(sorted) C --> o3((流)) o3 --> D(map) D --> E[result]

Java8中的集合支持一个新的Stream方法,它会返回一个。什么是流呢?简单的定义,就是“从支持数据处理操作的源生成的元素序列”:

  • 元素列表 —— 和集合一样,流也提供了一个接口,可以访问特定元素类型的一组有序值
  • —— 获取数据的源,比如集合。
  • 数据处理操作 —— 流更偏向于数据处理和计算,比如filter、map、reduce、find、match、sort等。

简单来说,我们通过一个集合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 所有元素求和

流的应用

以下总结了一些开发中接触到的一些流的简单应用:

List转Map

// area 按照 code 和 name 构建map
List<Area> areaList = new ArrayList();
...
Map<String, String> areaCodeNameMap = areaList.stream().collect(Collectors.toMap(Area::getCode, Area::getName));

List归类为Map

// 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()

猜你喜欢

转载自www.cnblogs.com/wxlzzz/p/11421604.html