不得不说,使用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, 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,可以调用相应的mapToDoublemapToLong,如下所示:

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,提取集合中的某一列/按条件过滤集合/求和/最大值/最小值/平均值的更多相关文章

  1. java正则表达式提取地址中的ip和端口号

    由于我需要用到java正则表达式提取地址中的ip和端口号,所以我就写了一个demo,测试一下,下面是demo public class Test0810_1 { public static void ...

  2. 黑马基础阶段测试题:创建一个存储字符串的集合list,向list中添加以下字符串:”C++”、”Java”、” Python”、”大数据与云计算”。遍历集合,将长度小于5的字符串从集合中删除,删除成功后,打印集合中的所有元素

    package com.swift; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; ...

  3. Day_11【集合】扩展案例2_使用普通for循环获取集合中索引为3的元素并打印,统计集合中包含字符串"def"的数量,删除集合中的所有字符串",将集合中每个元素中的小写字母变成大写字母def",

    分析以下需求,并用代码实现 1.定义ArrayList集合,存入多个字符串"abc" "def" "efg" "def" ...

  4. java8 按条件过滤集合

    //黄色部分为过滤条件list.stream().filter(user-> user.getId() > 5 && "1组".equals(user. ...

  5. 使用Java正则表达式提取字符串中的数字一例

    直接上代码: String reg = "\\D+(\\d+)$"; //提取字符串末尾的数字:封妖塔守卫71 == >> 71 String s = monster. ...

  6. Java 正则表达式提取标签中的属性(src 连接地址)等

    public class Test { public static void main(String[] args) { String source = "<p><img ...

  7. java 正则提取字符串中的电话号码

    public static void test2() { String str = "张三:13539558064,李四:15626829748,赵六:13718952204"; ...

  8. java8 list转map,list集合中的元素的属性转set,list集合中对象的属性转list

    一.使用java8对list操作 1.1list转map private Map<String, Member> getMemberMap() { List<Member> m ...

  9. List<Map<String, Object>>集合中获取某个key并转换为List<Integer>集合

    package com.codyy.sso.controller.yuanqu; import java.util.ArrayList; import java.util.HashMap; impor ...

随机推荐

  1. Testflight无法接入App Store connect,对TF上架的应用会造成什么影响吗?

    感觉进入8月份以来,苹果也进入了多事之秋.不仅是App Store被下架,testflight也频频出问题,很多人反馈出现了Testflight无法接入App Store connect的问题,我们之 ...

  2. Virtuoso 中如何优化 Library Manager 的显示

    https://www.cnblogs.com/yeungchie/ 主要从 cds.lib 文件去入手. 假设现在想把 Virtuoso 预装的库整理到 preload 分类(库)中. 首先创建一个 ...

  3. 图神经网络 PyTorch Geometric 入门教程

    简介 Graph Neural Networks 简称 GNN,称为图神经网络,是深度学习中近年来一个比较受关注的领域.近年来 GNN 在学术界受到的关注越来越多,与之相关的论文数量呈上升趋势,GNN ...

  4. python 基础-文件读写'r' 和 'rb'区别

    原文链接: python基础-文件读写'r' 和 'rb'区别 一.Python文件读写的几种模式: r,rb,w,wb 那么在读写文件时,有无b标识的的主要区别在哪里呢? 1.文件使用方式标识 'r ...

  5. Logistic回归分析之二元Logistic回归

    在研究X对于Y的影响时,如果Y为定量数据,那么使用多元线性回归分析(SPSSAU通用方法里面的线性回归):如果Y为定类数据,那么使用Logistic回归分析. 结合实际情况,可以将Logistic回归 ...

  6. AcWing243一个简单的整数问题2(树状数组+差分+前缀和规律)

    题目地址:https://www.acwing.com/problem/content/244/ 题目描述: 给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一: 1.“C l r d ...

  7. 网站seo整站优化有什么优势

    http://www.wocaoseo.com/thread-314-1-1.html       现在很多企业找网络公司做网站优化,已经不再像以前那样做目标关键词,而是通过整站优化来达到企业营销目的 ...

  8. mysql建数据库的字符集与排序规则说明

    本文转自https://blog.csdn.net/qq_38224812/article/details/80745868,感谢作者,自己留存已备他日使用 1.字符集说明: 一般选择utf8.下面介 ...

  9. cordova 环境配制和创建插件

    环境配制 英文网站:http://cordova.apache.org/ 中文网站:http://cordova.axuer.com/ 安装Cordova Cordova的命令行运行在Node.js ...

  10. C++STL complex吃书使用指南

    说在前面: complex即为复数 使用c++自带的complex类型,首先要有<complex>头文件,还要使用std命名空间 声明方式: complex <T> a:  声 ...