热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用JavaStream,提取集合中的某一列/按条件过滤集合/求和/最大值/最小值/平均值

不得不说,使用JavaStream操作集合实在是太好用了,不过最近在观察生产环境错误日志时,发现偶尔会出现以下2个异常:java.lang.NullPointerException

不得不说,使用Java Stream操作集合实在是太好用了,不过最近在观察生产环境错误日志时,发现偶尔会出现以下2个异常:

  1. java.lang.NullPointerException
  2. java.util.NoSuchElementException

因此本篇博客总结下使用Java Stream的部分场景以及如何避免上述的2个异常:

  1. 提取集合中的某一列(普通提取、去重)
  2. 按条件过滤集合
  3. 求和
  4. 最大值/最小值/平均值

1. 数据准备

首先定义下Friend类:

package com.zwwhnly.springbootaction.model;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class Friend {
/** * 姓名 */
private String name;
/** * 年龄 */
private Integer age;
/** * 身高 */
private Long height;
/** * 所在城市 */
private String city;
/** * 体重 */
private BigDecimal weight;
public Friend(String name, Integer age, Long height, String city, BigDecimal weight) {
this.name = name;
this.age = age;
this.height = height;
this.city = city;
this.weight = weight;
}
}

然后初始化以下数据供后面使用:

public static List<Friend> getFriendList() {
List<Friend> friendList = new ArrayList<>();
friendList.add(new Friend("小周", 28, 175L, "郑州", new BigDecimal("101.5")));
friendList.add(new Friend("小吴", 28, 170L, "洛阳", new BigDecimal("111.5")));
friendList.add(new Friend("小郑", 29, 176L, "郑州", new BigDecimal("121.5")));
friendList.add(new Friend("小王", 29, 180L, "北京", new BigDecimal("130")));
friendList.add(new Friend("小赵", 27, 178L, "苏州", new BigDecimal("140")));
friendList.add(new Friend("小钱", null, null, "杭州", new BigDecimal("150")));
return friendList;
}

2. 提取集合中的某一列

2.1 普通提取

比如,我们需要提取出所有朋友的姓名,可以使用Stream的map()方法,实现代码如下所示:

List<Friend> friendList = getFriendList();
List<String> nameList = friendList.stream().map(Friend::getName).collect(Collectors.toList());
nameList.forEach(name -> System.out.println(name));

输出结果:

小周

小吴

小郑

小王

小赵

2.2 提取后去重

比如,我们需要提取出所有朋友的年龄,但是需要去重,可以使用Stream的distinct()方法,实现代码如下所示:

List<Friend> friendList = getFriendList();
List<Integer> ageList = friendList.stream().map(Friend::getAge).distinct().collect(Collectors.toList());
ageList.forEach(age -> System.out.println(age));

输出结果:

28

29

27

3. 按条件过滤集合

比如,我们需要获取所有朋友中年龄在29岁以下,并且身高在170以上的朋友,可以调用filter方法,实现代码如下所示:

List<Friend> friendList = getFriendList();
List<Friend> youngPeople = friendList.stream()
.filter(friend -> friend.getAge() != null && friend.getAge() < 29 &&
friend.getHeight() != null && friend.getHeight() > 170L)
.collect(Collectors.toList());
System.out.println(youngPeople);

输出结果:

Friend(name=小周, age=28, 小钱",null,178,"杭州"));

然后,我们不过滤null数据,直接调用mapToInt方法,就会抛出java.lang.NullPointerException异常:

List<Friend> friendList = getFriendList();
int ageSum = friendList.stream().mapToInt(Friend::getAge).sum();
System.out.println(ageSum);

《使用Java Stream,提取集合中的某一列/按条件过滤集合/求和/最大值/最小值/平均值》

如果字段类型是Long或者Double,可以调用相应的mapToDoublemapToLong,如下所示:

《使用Java Stream,提取集合中的某一列/按条件过滤集合/求和/最大值/最小值/平均值》

4.2 BigDecimal

和Integer、Long、Double类型不同,如果字段类型是BigDecimal,求和的话需要调用reduce方法,使用方法如下所示:

List<Friend> friendList = getFriendList();
BigDecimal weightSum = friendList.stream()
.filter(friend -> friend.getWeight() != null)
.map(Friend::getWeight)
.reduce(BigDecimal.ZERO, BigDecimal::add);
System.out.println(weightSum);

输出结果:

754.5

注意事项:

为避免java.lang.NullPointerException异常,上面代码中的.filter(friend -> friend.getWeight() != null)也要记得加。

5. 最大值/最小值/平均值

5.1 Integer,Long,Double

比如,我们需要获取所有朋友中身高的最大值,实现代码如下所示:

List<Friend> friendList = getFriendList();
long heightMax = friendList.stream()
.filter(friend -> friend.getHeight() != null)
.mapToLong(Friend::getHeight)
.max().orElse(0);
System.out.println(heightMax);

输出结果:

180

注意事项:

因为max()方法的返回值是OptionalLong类型,所以我们需要继续调用orElse()方法设置个默认值,这里不要直接使用getAsLong()方法,因为当集合为空时,会抛出你肯定遇到过的java.util.NoSuchElementException异常:

long heightMax = friendList.stream()
.filter(friend -> friend.getHeight() != null)
.mapToLong(Friend::getHeight)
.max().getAsLong();

《使用Java Stream,提取集合中的某一列/按条件过滤集合/求和/最大值/最小值/平均值》

orElse()源码如下所示:

public long orElse(long other) {
return isPresent ? value : other;
}

getAsLong()源码如下所示:

public long getAsLong() {
if (!isPresent) {
throw new NoSuchElementException("No value present");
}
return value;
}

类似地,获取最小值的代码如下所示:

List<Friend> friendList = getFriendList();
long heightMin = friendList.stream()
.filter(friend -> friend.getHeight() != null)
.mapToLong(Friend::getHeight)
.min().orElse(0);
System.out.println(heightMin);

获取平均值的代码如下所示:

List<Friend> friendList = getFriendList();
double heightAverage = friendList.stream()
.filter(friend -> friend.getHeight() != null)
.mapToLong(Friend::getHeight)
.average().orElse(0D);
System.out.println(heightAverage);

5.2 BigDecimal

比如,我们需要获取所有朋友中体重的最大值,实现代码如下所示:

List<Friend> friendList = getFriendList();
BigDecimal weightMax = friendList.stream()
.filter(friend -> friend.getWeight() != null)
.map(Friend::getWeight)
.max(BigDecimal::compareTo)
.orElse(BigDecimal.ZERO);
System.out.println(weightMax);

输出结果:

150

注意事项:

1)为避免出现java.lang.NullPointerException异常,注意过滤体重为null的数据

2)因为max()方法的返回值为Optional类型,所以我们需要继续调用orElse()方法设置个默认值,这里不要直接使用get()方法,因为当集合为空时,会抛出你肯定遇到过的java.util.NoSuchElementException异常:

BigDecimal weightMax = friendList.stream()
.filter(friend -> friend.getWeight() != null)
.map(Friend::getWeight)
.max(BigDecimal::compareTo)
.get();

《使用Java Stream,提取集合中的某一列/按条件过滤集合/求和/最大值/最小值/平均值》

get()方法源码如下所示:

public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}

类似地,获取最小值的代码如下所示:

List<Friend> friendList = getFriendList();
BigDecimal weightMax = friendList.stream()
.filter(friend -> friend.getWeight() != null)
.map(Friend::getWeight)
.min(BigDecimal::compareTo)
.orElse(BigDecimal.ZERO);
System.out.println(weightMax);

6. 总结

使用Java Stream操作集合非常便利,但还是容易踩一些坑,比如文中提到的java.lang.NullPointerException异常和java.util.NoSuchElementException异常,所以使用时要多多注意,能不踩坑就不踩坑,就算踩坑,也别多次踩同一个坑。

注:如果觉得本篇博客有任何错误或者更好的建议,欢迎留言,我会及时跟进并更正博客内容!


推荐阅读
author-avatar
有拼搏精神的芒果tje
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有