使用Java Stream,提取集合中的某一列/按条件过滤集合/求和/最大值/最小值/平均值
不得不说,使用Java Stream操作集合实在是太好用了,不过最近在观察生产环境错误日志时,发现偶尔会出现以下2个异常:
- java.lang.NullPointerException
- java.util.NoSuchElementException
因此本篇博客总结下使用Java Stream的部分场景以及如何避免上述的2个异常:
- 提取集合中的某一列(普通提取、去重)
- 按条件过滤集合
- 求和
- 最大值/最小值/平均值
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, height=175, city=郑州, weight=101.5)
Friend(name=小赵, age=27, height=178, city=苏州, weight=140)
4. 求和
4.1 Integer,Long,Double
比如,我们需要计算出所有朋友的年龄之和,可以调用mapToInt
方法,实现代码如下所示:
List<Friend> friendList = getFriendList();
int ageSum = friendList.stream().filter(friend -> friend.getAge() != null).mapToInt(Friend::getAge).sum();
System.out.println(ageSum);
输出结果:
141
注意事项:
因为我们的age字段定义的是包装类型Integer
,但求和之后的返回类型为基本类型int
,所以在调用mapToInt
方法之前,一定要过滤掉年龄为null
的数据,否则分分钟抛异常。
比如,我们添加一条年龄为null
的数据:
friendList.add(new Friend("小钱",null,178,"杭州"));
然后,我们不过滤null数据,直接调用mapToInt
方法,就会抛出java.lang.NullPointerException
异常:
List<Friend> friendList = getFriendList();
int ageSum = friendList.stream().mapToInt(Friend::getAge).sum();
System.out.println(ageSum);
如果字段类型是Long
或者Double
,可以调用相应的mapToDouble
、mapToLong
,如下所示:
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();
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();
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
异常,所以使用时要多多注意,能不踩坑就不踩坑,就算踩坑,也别多次踩同一个坑。
使用Java Stream,提取集合中的某一列/按条件过滤集合/求和/最大值/最小值/平均值的更多相关文章
- java正则表达式提取地址中的ip和端口号
由于我需要用到java正则表达式提取地址中的ip和端口号,所以我就写了一个demo,测试一下,下面是demo public class Test0810_1 { public static void ...
- 黑马基础阶段测试题:创建一个存储字符串的集合list,向list中添加以下字符串:”C++”、”Java”、” Python”、”大数据与云计算”。遍历集合,将长度小于5的字符串从集合中删除,删除成功后,打印集合中的所有元素
package com.swift; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; ...
- Day_11【集合】扩展案例2_使用普通for循环获取集合中索引为3的元素并打印,统计集合中包含字符串"def"的数量,删除集合中的所有字符串",将集合中每个元素中的小写字母变成大写字母def",
分析以下需求,并用代码实现 1.定义ArrayList集合,存入多个字符串"abc" "def" "efg" "def" ...
- java8 按条件过滤集合
//黄色部分为过滤条件list.stream().filter(user-> user.getId() > 5 && "1组".equals(user. ...
- 使用Java正则表达式提取字符串中的数字一例
直接上代码: String reg = "\\D+(\\d+)$"; //提取字符串末尾的数字:封妖塔守卫71 == >> 71 String s = monster. ...
- Java 正则表达式提取标签中的属性(src 连接地址)等
public class Test { public static void main(String[] args) { String source = "<p><img ...
- java 正则提取字符串中的电话号码
public static void test2() { String str = "张三:13539558064,李四:15626829748,赵六:13718952204"; ...
- java8 list转map,list集合中的元素的属性转set,list集合中对象的属性转list
一.使用java8对list操作 1.1list转map private Map<String, Member> getMemberMap() { List<Member> m ...
- List<Map<String, Object>>集合中获取某个key并转换为List<Integer>集合
package com.codyy.sso.controller.yuanqu; import java.util.ArrayList; import java.util.HashMap; impor ...
随机推荐
- LNK2005 连接错误解决办法 2009-10-30 12:13
nafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@ ...
- 基于Prometheus和Grafana打造业务监控看板
前言 业务监控对许许多多的场景都是十分有意义,业务监控看板可以让我们比较直观的看到当前业务的实时情况,然后运营人员可以根据这些情况及时对业务进行调整操作,避免业务出现大问题. 老黄曾经遇到过一次比较尴 ...
- 浏览器自动化的一些体会4 webBrowser控件之零碎问题2
1. DocumentCompleted的多次执行问题 有的网页,会多次触发DocumentCompleted事件,由于它是异步的,不会阻塞,所以如果不恰当处理,会造成某些代码被错误地多次执行,造成意 ...
- 使用正则表达式限制<kbd>QLineEdit</kbd>不能输入大于某个整数
使用正则表达式限制QLineEdit不能输入大于某个整数,即:使用正则表达式,匹配不大于某个整数 举例:匹配不大于4567 * 原理分析: 匹配不大于4567这个数,所以第一个想到的是只要小于4567 ...
- [PyTorch 学习笔记] 1.3 张量操作与线性回归
本章代码:https://github.com/zhangxiann/PyTorch_Practice/blob/master/lesson1/linear_regression.py 张量的操作 拼 ...
- 解决SpringBoot页面跳转无法访问静态资源的问题
初学SpringBoot,写项目的时候遇到了问题,原本的页面是这样的 但启动项目后是这样的 这是因为thymeleaf中引入静态资源及模板需要使用到 th:xxx 属性,否则无法在动态资源中访问静态资 ...
- Jmeter 常用函数(23)- 详解 __longSum
如果你想查看更多 Jmeter 常用函数可以在这篇文章找找哦 https://www.cnblogs.com/poloyy/p/13291704.htm 作用 计算两个或多个长值的和 注意 当值不在 ...
- 通过自定义资源扩展Kubernetes
原文链接:通过自定义资源扩展Kubernetes
- Sign in with Apple 流程总结
流程图 相关说明 UserId 与用户的 Apple Id 一一对应.在同一个开发帐号下的所有 app 里,获取到的值都一样. IdentityToken identityToken 是一个 Json ...
- 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解
数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...