Java聚合操作(Aggregate Operations)是对一堆数据进行处理的新的操作方法,我们知道,如果想对一堆数据进行处理,比如一个List对象中的数据进行处理,传统的操作就是遍历List数据然后进行处理;现在有一种新的可以提供相同功能的操作方法,就是聚合操作(Aggregate Operations),它常与与lambda表达式绑定使用,在lambda表达式使用总结一节已经使用到了,这里举一个例子,如下代码,要求打印出List列表中性别为MALE的对象信息:

public class Main {
public static void main(String[] args) {
Person[] pers = {new Person(12, "h1",Person.Sex.FEMALE),
new Person(23, "h2",Person.Sex.MALE),
new Person(14, "h3",Person.Sex.FEMALE),
new Person(2, "h4",Person.Sex.MALE)};
List<Person> personList= Arrays.asList(pers);
//传统的for-each操作
for(Person p: personList){
if(p.getGender()== Person.Sex.MALE){
System.out.print(p+" ");
}
}
System.out.println("\n--------分割线--------");
//聚合操作
personList.stream().filter(obj->obj.getGender()==Person.Sex.MALE).forEach(obj->System.out.print(obj+" "));
}
}
@Data
@ToString
class Person{
int age;
String name;
Sex gender;
public Person(int age,String name,Sex gender){
this.age=age;
this.name=name;
this.gender=gender;
}
public Person(int age,String name){
this.age=age;
this.name=name;
}
public enum Sex {
MALE,FEMALE
}
}

上面的代码中,聚合操作的代码只一行就解决问题了,聚合操作涉及到两个概念:管道(pipeline)和流(stream),解释如下

管道(pipeline)是作用在源数据上的一些聚合操作,可以理解为数据源和多个聚合操作符号的组合,如上面的filter、forEach,一个管道包含以下内容:
1、一个数据源:可以是一个collection,array,生成函数,或则IO channel,本例中是一个集合。
2、0个或则多个中间操作,例如filter,可以产生一个新的流。
3、一个终止操作,例如forEach,产生一个非流的结果(non-stream result)。

流(stream)是一个个的元素,它不是某种数据结构,不用于存储数据,它的作用就是通过管道从数据源获取并传输数据,在上面的代码中集合personList通过调用stream()方法生成一个流。

归约操作:返回一个结果对象的操作,例如下面的示例:

double average = roster

    .stream()
.filter(p -> p.getGender() == Person.Sex.MALE)
.mapToInt(Person::getAge)
.average()
.getAsDouble(); 

上面的示例中,计算出所有男性对象的一个平均年龄,在聚合操作(aggregate operation)中有很多终止操作(terminal operation)只返回一个结果,这样的操作就是归约操作(reduction operation),除了返回一个值之外,还有一些归约操作返回一个集合对象。JDK提供了一个一般性的归约操作:reduce和collect方法。具体使用如下:

1、reduce方法,以一个示例引用使用方法,例如求所有人的年龄和:

Integer totalAge = roster
.stream()
.mapToInt(Person::getAge)
.sum();
Integer totalAgeReduce = roster
.stream()
.map(Person::getAge)
.reduce(
0,
(a, b) -> a + b);

上面的示例中的两种计算方法得出的结果是一样的,更多的使用案例可参考:https://www.cnblogs.com/qinhao517/p/9197885.html

2、collect方法,reduce是产生一个新值,而collect方法是来修改一个已经存在的值,还是上面的求平均年龄为例,我们可以创建一个对象用于存储计算结果:

class Averager implements IntConsumer{

    private int total = 0;
private int count = 0;
public double average() {
return count > 0 ? ((double) total)/count : 0;
}
public void accept(int i) { total += i; count++; }
public void combine(Averager other) {
total += other.total;
count += other.count;
}
}
Averager averageCollect = roster.stream()
.filter(p -> p.getGender() == Person.Sex.MALE)
.map(Person::getAge)
.collect(Averager::new, Averager::accept, Averager::combine); System.out.println("Average age of male members: " +
averageCollect.average()); 

上面的计算中,collect传入了三个参数,返回了一个Averager对象,传入的三个参数分别是:

supplier:是一个工厂函数,用于创建新的实例对象

accumulator:累加器函数用于将一个流元素合成一个结果容器,在这个示例中,它通过给count变量加一和将流元素(stream element)中的值(getAge方法获取到的年龄)加给total来修改Averager的结果

combiner:合并函数拿出两个结果容器(result container)来合并他们的内容,在这个示例中,它通过将其他结果容器的count值和total值累加到自己的(Averager::new 创建的对象)元素中来生成最终的结果

上面的示例中,filter方法过滤出所有男性的对象,map方法通过getAage获取年龄将人的对象单个的流对象映射成一个年龄值,collect方法通过这些年龄值的运算返回一个最终的结果,结果值是利用Averager对象最为媒介来返回的。

collect还可以将对象中的某个值抽取出来作为一个list返回给用户:

List<String> namesOfMaleMembersCollect = roster
.stream()
.filter(p -> p.getGender() == Person.Sex.MALE)
.map(p -> p.getName())
.collect(Collectors.toList());

除了上面的操作,下面还有其他的示例:

Map<Person.Sex, List<Person>> byGender =
roster
.stream()
.collect(
Collectors.groupingBy(Person::getGender));

上面的示例中,是通过性别,将不同的对象放到各自性别的List集合中,那我只想获取不同性别的对象的名字呢?

Map<Person.Sex, List<String>> namesByGender =
roster
.stream()
.collect(
Collectors.groupingBy(
Person::getGender,
Collectors.mapping(
Person::getName,
Collectors.toList())));

也可以获取每个性别的所有对象的年龄之和:

Map<Person.Sex, Integer> totalAgeByGender =
roster
.stream()
.collect(
Collectors.groupingBy(
Person::getGender,
Collectors.reducing(
0,
Person::getAge,
Integer::sum)));

上面的操作更复杂一些,reducing函数进行归约操作,上面的0是一个计算的基础标识,在此标识的基础上进行操作(operation),至于什么操作,第三个参数的Integer::sum给出了答案,Person::getAge对应的是一个mapper操作,该mapper利用getAge方法抽取出年龄。

Map<Person.Sex, Double> averageAgeByGender = roster
.stream()
.collect(
Collectors.groupingBy(
Person::getGender,
Collectors.averagingInt(Person::getAge)));

上面的是计算每个性别的年龄平均值。

还有其他很多类型的聚合操作,一个语法的熟练掌握还是需要靠实践来完成....

Java8-聚合操作的更多相关文章

  1. 大数据项目2(Java8聚合操作)

    前言:为很好的理解这些方法,你需要熟悉java8特性Lambda和方法引用的使用 一:简介 我们用集合的目的,往往不是简单的仅仅把数据保存哪里.而是要检索(遍历)或者去计算或统计....操作集合里面的 ...

  2. Java8中聚合操作collect、reduce方法详解

    Stream的基本概念 Stream和集合的区别: Stream不会自己存储元素.元素储存在底层集合或者根据需要产生.Stream操作符不会改变源对象.相反,它会返回一个持有结果的新的Stream.3 ...

  3. Java8之Stream 集合聚合操作集锦(含日常练习Demo)

    Stream 是用函数式编程方式在集合类上进行复杂操作的工具,其集成了Java 8中的众多新特性之一的聚合操作,开发者可以更容易地使用Lambda表达式,并且更方便地实现对集合的查找.遍历.过滤以及常 ...

  4. JDK1.8聚合操作

    在java8 JDK包含许多聚合操作(如平均值,总和,最小,最大,和计数),返回一个计算流stream的聚合结果.这些聚合操作被称为聚合操作.JDK除返回单个值的聚合操作外,还有很多聚合操作返回一个c ...

  5. 《Entity Framework 6 Recipes》中文翻译系列 (27) ------ 第五章 加载实体和导航属性之关联实体过滤、排序、执行聚合操作

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-9  关联实体过滤和排序 问题 你有一实体的实例,你想加载应用了过滤和排序的相关 ...

  6. MongoDB 聚合操作

    在MongoDB中,有两种方式计算聚合:Pipeline 和 MapReduce.Pipeline查询速度快于MapReduce,但是MapReduce的强大之处在于能够在多台Server上并行执行复 ...

  7. .NET LINQ 聚合操作

    聚合操作      聚合运算从值集合计算单个值. 从一个月的日温度值计算日平均温度就是聚合运算的一个示例. 方法 方法名 说明 C# 查询表达式语法 Visual Basic 查询表达式语法 更多信息 ...

  8. Linq查询操作之聚合操作(count,max,min,sum,average,aggregate,longcount)

    在Linq中有一些这样的操作,根据集合计算某一单一值,比如集合的最大值,最小值,平均值等等.Linq中包含7种操作,这7种操作被称作聚合操作. 1.Count操作,计算序列中元素的个数,或者计算满足一 ...

  9. OpenStack/Gnocchi简介——时间序列数据聚合操作提前计算并存储起来,先算后取的理念

    先看下 http://www.cnblogs.com/bonelee/p/6236962.html 这里对于环形数据库的介绍,便于理解归档这个操作! 转自:http://blog.sina.com.c ...

  10. ElasticSearch 学习记录之ES几种常见的聚合操作

    ES几种常见的聚合操作 普通聚合 POST /product/_search { "size": 0, "aggs": { "agg_city&quo ...

随机推荐

  1. AD中添加原理图文档模板-转载

    (24条消息) AD中添加原理图文档模板_shuguang552的博客-CSDN博客_ad原理图模板

  2. spider_object_01使用正则爬取百度贴吧所有内容保存成html

    """本案例不涉及数据提取,仅指导 网页分页爬取的两种方式 思路非第一种:利用while Ture,传参,然后在设定一个判断条件,案例中用的是如果找不到下一页,循环退出( ...

  3. Linux命令之nc命令

    1.简介 nc是netcat的简写,是一个功能强大的网络工具,有着网络界的瑞士军刀美誉.nc命令在linux系统中实际命令是ncat,nc是软连接到ncat.nc命令的主要作用如下: 实现任意TCP/ ...

  4. pycharm导入第三方包

  5. 内部类(Java)

    内部类 基本介绍 概念:在一个类的内部再定义一个完整类 特点:编译之后可生成独立的字节码文件:内部类可以直接访问外部类的私有属性,不破坏封装性 分类:成员内部类:静态内部类:局部内部类:匿名内部类 p ...

  6. 用shell开火车哈哈

    用shell开火车!(σ゚∀゚)σ⁶⁶⁶⁶⁶⁶⁶⁶⁶⁶ while true; do sl -aFile; done 这个效果更佳

  7. Longest Common Substring(最长公共子串)

    SP1811 题目描述 A string is finite sequence of characters over a non-empty finite set Σ. In this problem ...

  8. 【cs231n】knn作业笔记

    完成了assignment-1中knn相关内容的作业,记录一下遇到的知识点和问题 knn.ipynb的内容大致包括: 1.数据集的建立 主要是通过切片函数,如下图选取前5000张图片和其标记作为训练数 ...

  9. CentOS基本命令手册

    一.磁盘使用情况 两个命令df .du结合比较直观 df -h #查看整台服务器的硬盘使用情况 du -sh * #查看每个文件夹的大小 二.tar 用法 压缩 tar tar -czvf test. ...

  10. C/C++ 数据结构单链表的实现(初始化、插入、删除、销毁)

    #include <iostream> #include <Windows.h> #define MAX_SIZE 100 using namespace std; //单链表 ...