Stream——对集合某个字段数据求和

1年前 (2022) 程序员胖胖胖虎阿
143 0 0

文章目录

  • 前言
  • 定义数据接收类
  • 定义测试数据
  • 数据筛选
    • 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类型的数据类型,无法采取mapToDoublemapToLongmapToInt进行操作。

如果数据类型为DoubleLongInt,进行集合数据字段求和操作,可以采取下列方式进行:

// double/long 需要注意此处
int sum = widgets
			.stream()
			.filter(w -> w.getColor() == RED)
			.mapToInt(w -> w.getWeight()) 
			//.mapToDouble(w -> w.getWeight()) 
			//.mapToLong(w -> w.getWeight()) 
			.sum();  

版权声明:程序员胖胖胖虎阿 发表于 2022年11月24日 下午4:24。
转载请注明:Stream——对集合某个字段数据求和 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...