文章目录
- 前言
- 定义数据接收类
- 定义测试数据
- 数据筛选
-
- 1、数据集合判空
-
- 1.1、Optional.isPresent()
- 1.2、orElse 替换
- 2、获取集合中类元属性信息并求和
- 你以为这样就结束了?
- 扩充
前言
之前,针对Stream
链式编程中的几个方法做了大致的说明。详情可以参考:
JDK 1.8 新特性之Stream 详解个人笔记
但实际业务中,总会存在很多复杂的思维,需要使用到Stream
,此时玩的不熟练总感觉无从下手。
以几个案例的形式,展示一些使用流来实现的操作,做一个笔记的记录。
定义数据接收类
因为要考虑使用集合,需要使用到自定义类对象,所以先从定义对象开始。
public class User {
private String name;
private BigDecimal age;
private Integer num;
public User(String name, BigDecimal age) {
this.name = name;
this.age = age;
}
public User(String name, BigDecimal age, Integer num) {
this.name = name;
this.age = age;
this.num = num;
}
// get/set
// toString()
}
定义测试数据
自定义数据集合,模拟数据库查询到的数据信息。
List<User> users = Arrays.asList(
new User("xj1", new BigDecimal(1)),
new User("xj2", new BigDecimal(3)),
new User("xj3", new BigDecimal(5)),
new User("xj4", new BigDecimal(7)));
数据筛选
这里时模拟数据,采取手动定义,所以数据一定存在
。
如果数据是从数据库中查询,此时这里的
users 集合 可能为 null
当出现null.stream()
时,会出现NPE
报错信息!为了保证代码的健壮性,需要对数据信息进行判空。
1、数据集合判空
常见的stream判空有两种。
1.1、Optional.isPresent()
System.out.println("-----> " + Optional.ofNullable(null).isPresent());
System.out.println("-----> " + Optional.ofNullable(new ArrayList<>()).isPresent());
结果:
-----> false
-----> true
可以通过Optional.ofNullable(集合别名).isPresent()
判断集合是否存在
,再通过返回 boolean
判断是否继续向下执行链式编程代码。
1.2、orElse 替换
还有一种方式,是如果存在空对象
,则将空对象进行替换操作
。如下所示:
public class Test {
public static void main(String[] args) {
List<User> users = Arrays.asList(
new User("xj1", null),
new User("xj2", null),
new User("xj3", null),
new User("xj4", null));
System.out.println(Optional.ofNullable(users).orElse(new ArrayList<>()));
System.out.println(Optional.ofNullable(null).orElse(new ArrayList<>()));
}
}
结果:
[User{name='xj1', age=null, num=null}, User{name='xj2', age=null, num=null}, User{name='xj3', age=null, num=null}, User{name='xj4', age=null, num=null}]
[]
2、获取集合中类元属性信息并求和
由于集合中的元数据为User 类
,真正需要求和的是age 属性
,所以需要使用到stream
中的map
将待处理的属性归集出来
.
此时使用map
后,数据依旧是一个流的形态,可以采取reduce
进行求和
操作。
List<User> users = Arrays.asList(
new User("xj1", new BigDecimal(1)),
new User("xj2", new BigDecimal(3)),
new User("xj3", new BigDecimal(5)),
new User("xj4", new BigDecimal(7)));
BigDecimal reduce = Optional.ofNullable(users)
.orElse(new ArrayList<>())
.stream()
.map(User::getAge)
.reduce(BigDecimal.ZERO, BigDecimal::add);
System.out.println(reduce);
结果:
16
你以为这样就结束了?
如果存在其中一个值为null
,会自动将null
当作0
处理吗?
List<User> users = Arrays.asList(
new User("xj1", new BigDecimal(1)),
new User("xj2", null),
new User("xj3", new BigDecimal(5)),
new User("xj4", new BigDecimal(7)));
BigDecimal reduce = Optional.ofNullable(users)
.orElse(new ArrayList<>())
.stream()
.map(User::getAge)
.reduce(BigDecimal.ZERO, BigDecimal::add);
System.out.println(reduce);
结果:
Exception in thread "main" java.lang.NullPointerException
at java.math.BigDecimal.add(BigDecimal.java:1288)
at java.util.stream.ReduceOps$1ReducingSink.accept(ReduceOps.java:80)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java:474)
at xj.test.streams.Test.main(Test.java:30)
出现这种问题的原因就在于:
数据列中存在null的数据信息,导致出现
NPE
报错!
只需要将数据筛选出来就可以了,解决方式如下所示:
List<User> users = Arrays.asList(
new User("xj1", new BigDecimal(1)),
new User("xj2", null),
new User("xj3", new BigDecimal(5)),
new User("xj4", new BigDecimal(7)));
BigDecimal reduce = Optional.ofNullable(users)
.orElse(new ArrayList<>())
.stream()
.filter(x-> x.getAge() != null) // 避免空指针
.map(User::getAge)
.reduce(BigDecimal.ZERO, BigDecimal::add);
System.out.println(reduce);
结果:
13
扩充
针对BigDecimel
类型的数据类型,无法采取mapToDouble
、mapToLong
、mapToInt
进行操作。
如果数据类型为Double
、Long
、Int
,进行集合数据字段求和操作,可以采取下列方式进行:
// double/long 需要注意此处
int sum = widgets
.stream()
.filter(w -> w.getColor() == RED)
.mapToInt(w -> w.getWeight())
//.mapToDouble(w -> w.getWeight())
//.mapToLong(w -> w.getWeight())
.sum();