Java 8 API 添加了一个新的抽象称为流 Stream,可以让你以一种声明的方式处理数据,它提供了非常强大Java 集合运算和表达的高阶抽象。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理,可以把它看成一个工厂,流水线的形式(假如是玩具厂)。在这个流水线上,工人们对每个过来的玩具,进行处理,比如筛选、组装等。
Stream API可以极大提高Java程序员的生产力,省时省力还优雅。
下面我们来看看它的常见用法:
List userIdList = userList.stream().map(User::getUserId).
collect(Collectors.toList());
这行代码可以将userList中的userId转换为流 再用.collect(Collectors.toList())方法 提取为一个List集合,非常的方便高效。
另外,有的小伙伴可能需要过滤空字符等,可以用Stream流的 filter() 方法
List userAddressList = userList.stream().map(User::getAddress).
filter(Objects::nonNull).
collect(Collectors.toList());
这行代码 可以将userList的地址提取出来,且过滤掉地址为空的user对象。
1、转换成对象某一字段与对象的Map
示例代码如下:
Map userIdWithUserMap = userList.stream().
collect(Collectors.toMap(User::getUserId, User-> user));
这段代码可以以userId为key,user对象为value 组成一个map
2、转换成对象某一字段与对象另一字段的Map
示例代码如下:
Map userIdWithAgeMap = userList.stream().
collect(Collectors.toMap(User::getUserId, User::getAge));
List voList = userList.stream().map(item -> {
UserVo vo = new UserVo();
BeanUtils.copyProperties(item,vo);
//vo可以进行别的操作
//vo.set... 之类的
return vo;
}).collect(Collectors.toList());
上面这段代码通过Stream流的map()方法 可以将每个元素换成别的元素。可以将流看成一个流水线,userList的流一个一个过去 工人们将每个产品都将userList转换为 userVoList。 item是自定义名称 你也可以叫user 甚至a b c等(我不建议我不建议我不建议)
里面是使用了BeanUtils.copyProperties(item,vo); 来进行属性复制的操作。将item对象的属性赋值给vo对象。需要注意的是 item和vo的字段名需要对上 否则无法赋值成功。比如user有id name age三个属性,vo是userId, userName, age 三个属性 这时只有age能成功赋值。别的需要自己去set。
我们偶尔会遇到想根据集合中的某个属性来进行排序的情况。
假设UserVo中 有个 distance 距离 属性。 我们想根据 distance 排序 怎么实现呢?
Stream流也可以做到:
List resultVoList = voList.stream()
.sorted(Comparator.comparingDouble(UserVo::getDistance))
.collect(Collectors.toList());
上面这行代码 使用了 Stream流的 sorted() 方法 将voList进行排序。 再使用.collect(Collectors.toList()); 将流转换为List集合。巧妙的实现了排序操作。
有些小伙伴可能有去重的需求,我们知道set结构是去重的。
那么我们可以利用Stream的Collectors.toSet()来进行
Set userIdSet = userList.stream()
.map(User::getUserId)
.collect(Collectors.toSet());
这段代码就提取出了userList的id,并去重 赋值为一个Set集合。
假设这是你的选手List,其中有 viewCount 是Long类型。那就可以如下:
List playerList = //
// 计算总的 viewCount
long totalViewCount = playerList.stream()
.mapToLong(Player::getViewCount)
.sum();
那如果是String类型呢:
long totalViewCount = playerList.stream()
.map(Player::getViewCount)
.filter(viewCount -> viewCount != null && !viewCount.isEmpty()) // 过滤空值
.mapToLong(Long::parseLong) // 转换为 Long 类型
.sum();
//有空会继续补充。。
另外有些小伙伴会有疑问说For循环 增强For循环 Stream流 这三个的效率区别 Stream会不会比较慢等。
基本上 三者对于List操作 循环效率差别不大。
一定要对比一下的话,在循环次数较少的时候,基本上是Stream流的效率最低。为什么说是基本上,啊因为它大部分情况最低的。但是Stream可以通过parallel()方法开启并行流,随着CPU核心数的提升,和一些合理的场景运用,则会越来越快,这跟它基于的Fork/join框架有关。这个框架简单来说就是将可以并行的任务拆分成更小的任务来并行。后续我再出一篇细讲。
损失的一丁点性能,换来的是代码非常大程度的整洁和优雅。我个人还是非常推荐大家使用Stream流的。
好了。这部分先到这里,还有需要了解什么场景,或者我有些说的不太准确的地方,欢迎大家留言指正。谢谢!