资讯专栏INFORMATION COLUMN

使用JAVA8 stream中三个参数的reduce方法对List进行分组统计

崔晓明 / 1871人阅读

摘要:背景平时在编写前端代码时,习惯使用来编写野生的提供来一套完整的对对象等进行操作,这其中就包括和,即分组和聚合不知道该怎么翻译合适。使用这些野生的能够极大的提高我本人编写代码的效率。

背景

平时在编写前端代码时,习惯使用lodash来编写‘野生’的JavaScript;

lodash提供来一套完整的API对JS对象(Array,Object,Collection等)进行操作,这其中就包括_.groupBy 和 _.reduce,即分组和"聚合"(reduce不知道该怎么翻译合适)。

使用这些‘野生’的API能够极大的提高我本人编写JS代码的效率。而JAVA8开始支持stream和lambda表达式,这些和lodash的API有很多类似的功能。因此我在熟悉lodash的前提下尝试使用JAVA8的新特性减少冗余代码的编写。

需求

在开发后端某功能接口的过程中,需要对一个从数据库中取出的数据List进行按照ID进行聚合统计

JAVA8 reduce API
API个人理解
   U reduce(U u,BiFunction accumulator,BinaryOperator combiner)
  #第一个参数返回实例u,传递你要返回的U类型对象的初始化实例u

  #第二个参数累加器accumulator,可以使用二元ℷ表达式(即二元lambda表达式),声明你在u上累加你的数据来源t的逻辑
  #例如(u,t)->u.sum(t),此时lambda表达式的行参列表是返回实例u和遍历的集合元素t,函数体是在u上累加t

  #第三个参数组合器combiner,同样是二元ℷ表达式,(u,t)->u
  #lambda表达式行参列表同样是(u,t),函数体返回的类型则要和第一个参数的类型保持一致
伪代码
  #1.声明一个返回结果U
  #2.对List进行遍历,在U和每个T实例上应用一个累加器进行累加操作
  #3.返回最终结果U
  U result = identity;
  for (T element : this stream)
      result = accumulator.apply(result, element)
  return result;
数据准备
var source =
[
    {"name": "A","type": "san","typeValue": 1.0,"count": 2},
    {"name": "A","type": "nas","typeValue": 13.0,"count": 1},
    {"name": "B","type": "san","typeValue": 112.0,"count": 3},
    {"name": "C","type": "san","typeValue": 43.0,"count": 5},
    {"name": "B","type": "nas","typeValue": 77.0,"count": 7}
];
var target =
[
    {
        "name": "A",
        "count": 3,
        "totalTypeValue": 14.0,
        "bazList": [
            {
                "type": "san",
                "typeValue": 1.0
            },
            {
                "type": "nas"
                "typeValue": 13.0
            }
        ]
    }, 
    {
        "name": "B",
        "count": 10,
        "totalTypeValue": 189.0,
        "bazList": [
            {
                "type": "san",
                "typeValue": 112.0
            }, {
                "type": "nas"
                "typeValue": 77.0
            }
        ]
    }, 
    {
        "name": "C",
        "count": 5,
        "totalTypeValue": 43.0,
        "bazList": [
            {
                "type": "san",
                "typeValue": 43.0
            }
        ]
    }
];
Code

讲了那么多废话,这个才是最直接的

代码执行大意

List 按照name分组统计得到 List

ReduceTest.java
import com.google.common.collect.Lists;
import Bar;
import Foo;

import java.util.List;
import java.util.stream.Collectors;


public class ReduceTest {
    
    public static void main(String[] args) throws Exception{
        List fooList = Lists.newArrayList(
            new Foo("A","san",1.0,2),
            new Foo("A","nas",13.0,1),
            new Foo("B","san",112.0,3),
            new Foo("C","san",43.0,5),
            new Foo("B","nas",77.0,7)
        );
        List barList = Lists.newArrayList();
        fooList
            .stream()
            .collect(Collectors.groupingBy(Foo::getName,Collectors.toList()))
            .forEach((name,fooListByName)->{
                Bar bar = new Bar();
                bar = fooListByName
                        .stream()
                        .reduce(bar,(u,t)->u.sum(t),(u,t)->u);
                System.out.println(bar.toString());
                barList.add(bar);
            });
    }
    /*
    输出结果
    name:A
    count:3
    totalTypeValue:14.0
    bazList:
        type:san
        typeValue:1.0
        type:nas
        typeValue:13.0
    
    name:B
    count:10
    totalTypeValue:189.0
    bazList:
        type:san
        typeValue:112.0
        type:nas
        typeValue:77.0
    
    name:C
    count:5
    totalTypeValue:43.0
    bazList:
        type:san
        typeValue:43.0
    */
}
Foo.java
public class Foo{
    private String name;
    private String type;
    private Double typeValue;
    private Integer count;

    public Foo(String name, String type, Double typeValue, Integer count) {
        this.name = name;
        this.type = type;
        this.typeValue = typeValue;
        this.count = count;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Double getTypeValue() {
        return typeValue;
    }

    public void setTypeValue(Double typeValue) {
        this.typeValue = typeValue;
    }

    public Integer getCount() {
        return count;
    }

    public void setCount(Integer count) {
        this.count = count;
    }
}
Bar.java
import com.google.common.collect.Lists;

import java.util.List;

public class Bar{
    private String name;
    private Integer count;
    private Double totalTypeValue;
    private List bazList;

    public Bar() {
        this.name = null;
        this.count = 0;
        this.totalTypeValue = 0.0;
        this.bazList = Lists.newArrayList();
    }

    public Bar sum(Foo foo){
        if(name == null){
            this.name = foo.getName();
        }
        this.count += foo.getCount();
        this.totalTypeValue += foo.getTypeValue();
        this.bazList.add(new Baz(foo.getType(),foo.getTypeValue()));
        return this;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getCount() {
        return count;
    }

    public void setCount(Integer count) {
        this.count = count;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("name:").append(this.name).append(System.lineSeparator());
        sb.append("count:").append(this.count).append(System.lineSeparator());
        sb.append("totalTypeValue:").append(this.totalTypeValue).append(System.lineSeparator());
        sb.append("bazList:").append(System.lineSeparator());
        this.bazList.forEach(baz->{
            sb.append("	").append("type:").append(baz.getType()).append(System.lineSeparator());
            sb.append("	").append("typeValue:").append(baz.getTypeValue()).append(System.lineSeparator());
        });
        return sb.toString();
    }
}
Baz.java
public class Baz{
    private String type;
    private Double typeValue;

    public Baz(String type, Double typeValue) {
        this.type = type;
        this.typeValue = typeValue;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Double getTypeValue() {
        return typeValue;
    }

    public void setTypeValue(Double typeValue) {
        this.typeValue = typeValue;
    }
}
PS

等下次有空补上不使用stream().reduce 实现同样操作的比较繁琐的代码,啦啦啦啦啦~~~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/66548.html

相关文章

  • Java8特性④Stream收集数据

    摘要:多级分组的为键,类型所对应的集合为值一级分类为的,二级分类为的按子集收集数据的为键,类型所对应的集合的为值分区分区是分组的特殊情况由一个谓词返回一个布尔值的函数作为分类函数,它称分区函数。 收集器可以简洁而灵活地定义collect用来生成结果集合的标准。更具体地说,对流调用 collect 方法将对流中的元素触发一个归约操作(由Collector来参数化)。一般来说,Collector...

    daryl 评论0 收藏0
  • 简洁方便集合处理——Java 8 stream

    摘要:打印结果结果按照年龄从小到大进行排序。打印结果果然,前两个人都被去除了,只剩下最老的葫芦娃爷爷。比如检测有没有来自巴黎的用户。可以根据用户所在城市进行分组结果是一个,为不重复的城市名,为属于该城市的用户列表。 背景 java 8已经发行好几年了,前段时间java 12也已经问世,但平时的工作中,很多项目的环境还停留在java1.7中。而且java8的很多新特性都是革命性的,比如各种集合...

    godiscoder 评论0 收藏0
  • Java8实战》-第六章读书笔记(用流收集数据-01)

    摘要:收集器用作高级归约刚刚的结论又引出了优秀的函数式设计的另一个好处更易复合和重用。更具体地说,对流调用方法将对流中的元素触发一个归约操作由来参数化。另一个常见的返回单个值的归约操作是对流中对象的一个数值字段求和。 用流收集数据 我们在前一章中学到,流可以用类似于数据库的操作帮助你处理集合。你可以把Java 8的流看作花哨又懒惰的数据集迭代器。它们支持两种类型的操作:中间操作(如 filt...

    EscapedDog 评论0 收藏0
  • Java8流特性和Lambda表达式

    摘要:表达式体现了函数式编程的思想,即一个函数亦可以作为另一个函数参数和返回值,使用了函数作参数返回值的函数被称为高阶函数。对流对象进行及早求值,返回值不在是一个对象。 Java8主要的改变是为集合框架增加了流的概念,提高了集合的抽象层次。相比于旧有框架直接操作数据的内部处理方式,流+高阶函数的外部处理方式对数据封装更好。同时流的概念使得对并发编程支持更强。 在语法上Java8提供了Lamb...

    gaara 评论0 收藏0
  • Java8创建Stream四种方式以及 Stream 间操作

    摘要:一创建里流的四种方式第一种通过得方法串行流或者方法并行流创建。终止操作时一次性全部处理,称为延迟加载筛选切片过滤中建操作。终止操作只有执行终止操作才会执行全部。即延迟加载结果中建操作。截断流,使其元素不超过给定数量。返回流中最大值。 Stream api **Stream api 是java8 中提供的对集合处理的api , 对数据进行一系列的中间操作,元数据不会发生改变 ...

    0xE7A38A 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<