前言:为很好的理解这些方法,你需要熟悉java8特性Lambda和方法引用的使用

一:简介

  我们用集合的目的,往往不是简单的仅仅把数据保存哪里。而是要检索(遍历)或者去计算或统计....操作集合里面的数据。现假设我有一个实体对象Person如下,用于测试集合操作

public class Person {
public enum Sex {
MALE, FEMALE
}
String name;
LocalDate birthday;
Sex gender;
String emailAddress; Person(String nameArg, LocalDate birthdayArg, Sex genderArg, String emailArg) {
name = nameArg;
birthday = birthdayArg;
gender = genderArg;
emailAddress = emailArg;
} public int getAge() {
return birthday.until(IsoChronology.INSTANCE.dateNow()).getYears();
} public void printPerson() {
System.out.println(name + ", " + this.getAge());
} public Sex getGender() {
return gender;
} public String getName() {
return name;
} public String getEmailAddress() {
return emailAddress;
} public LocalDate getBirthday() {
return birthday;
} public static int compareByAge(Person a, Person b) {
return a.birthday.compareTo(b.birthday);
} public static List<Person> createRoster() { List<Person> roster = new ArrayList<>();
roster.add(new Person("Fred", IsoChronology.INSTANCE.date(1980, 6, 20), Person.Sex.MALE, "fred@example.com"));
roster.add(new Person("Jane", IsoChronology.INSTANCE.date(1990, 7, 15), Person.Sex.FEMALE, "jane@example.com"));
roster.add(
new Person("George", IsoChronology.INSTANCE.date(1991, 8, 13), Person.Sex.MALE, "george@example.com"));
roster.add(new Person("Bob", IsoChronology.INSTANCE.date(2000, 9, 12), Person.Sex.MALE, "bob@example.com")); return roster;
} @Override
public String toString() {
return "Person [name=" + name + ", birthday=" + birthday + ", gender=" + gender + ", emailAddress="
+ emailAddress + "]";
} }

1.1 管道和流

NOTE: 管道是一个有序的聚合操作(A pipeline is a sequence of aggregate operations)

举例一:打印集合中所有性别为男性的名字

@Test
public void test1() {
roster.stream().filter(e -> e.getGender() == Person.Sex.MALE).forEach(e -> System.out.println(e.getName()));
}

当然你也可以用 for-each 循环做到这一点

分析:管道中包含了那些组件

一个数据源,即一个集合 roster

0个或多个中间操作,本例中只有一个.filter过滤集合中的男性。

一个终止操作,即forEach遍历并打印姓名,无返回值。

举例二:计算平均数,即计算集合中男性的平局年龄

@Test
public void test() {
double average = roster.stream().filter(p -> p.getGender() == Person.Sex.MALE).mapToInt(Person::getAge)
.average().getAsDouble();
System.out.println(average);
}

聚合过程  filter-->mapToInt-->average()-->getAsDouble

二:还原操作

Note:The JDK contains many terminal operations (such as averagesumminmax, and count) that return one value by combining the contents of a stream. These operations are called reduction operations.

还原操作:个人理解还原操作即一种终止某种过程或状态的操作,并转换成另外一种状态。在这里即是对流的终止操作,并转化为另一种状态(另一种状态即Double或Int....包括引用类型)

这里主要介绍两种  Stream.reduce和Stream.collect方法。

2.1:Stream.reduce 计算总和

方法一:通过sum() 聚合   roster.stream().mapToInt(Person::getAge).sum();

方法二:即通过Stream.reduce

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

NOTE: 0 可以改为任意Int数据,其作用就是在原总和的基础上加上0

2.2 :Stream.collect方法 还原成其他类型

举例一:计算平均数,还原成指定类型Averager

public class Averager implements IntConsumer {
private int total = 0;
private int count = 0; public double average() {
return count > 0 ? ((double) total) / count : 0;
} public double getTotal() {
return total;
} @Override
public void accept(int i) {
total += i;
count++;
} public void combine(Averager other) {
total += other.total;
count += other.count;
}
}

测试:

@Test
public void test3() {
SupplierImpl impl = new SupplierImpl();
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()); Averager averageCollect2 = roster.stream().filter(p -> p.getGender() == Person.Sex.MALE).map(Person::getAge)
.collect(impl, Averager::accept, Averager::combine);
System.out.println("Average age of male members22: " + averageCollect2.average());
}

The collect operation in this example takes three arguments:

  • supplier: The supplier is a factory function; it constructs new instances. For the collect operation, it creates instances of the result container. In this example, it is a new instance of the Averager class.
  • accumulator: The accumulator function incorporates a stream element into a result container. In this example, it modifies the Averager result container by incrementing the count variable by one and adding to the totalmember variable the value of the stream element, which is an integer representing the age of a male member.
  • combiner: The combiner function takes two result containers and merges their contents. In this example, it modifies an Averager result container by incrementing the count variable by the count member variable of the other Averager instance and adding to the total member variable the value of the other Averager instance's total member variable

举例二:Stream.collect方法 还原成List<String>

@Test
public void test5() {
List<String> namesOfMaleMembersCollect = roster.stream().filter(p -> p.getGender() == Person.Sex.MALE)
.map(p -> p.getName()).collect(Collectors.toList());
namesOfMaleMembersCollect.forEach(System.out::print);
System.out.println();
namesOfMaleMembersCollect.add("1234");
namesOfMaleMembersCollect.forEach(System.out::print);
}

举例三:Stream.collect方法  还原成Map<Object,List<Object>,

@Test
public void test6() {
Map<Sex, List<Person>> byGender = roster.stream().collect(Collectors.groupingBy(Person::getGender));
Set<Sex> keySet = byGender.keySet();
for (Sex sex : keySet) {
List<Person> list = byGender.get(sex);
System.out.println("sex = " + sex);
list.forEach(System.out::print);
System.out.println();
}
}

使用场景:对源数据进行分组

举例四:Stream.collect方法  还原成Map<Object,List>,

@Test
public void test7() {
Map<Person.Sex, List<String>> namesByGender = roster.stream().collect(
Collectors.groupingBy(Person::getGender, Collectors.mapping(Person::getName, Collectors.toList())));
Set<Sex> keySet = namesByGender.keySet();
for (Sex sex : keySet) {
List<String> list = namesByGender.get(sex);
System.out.println("sex = " + sex);
list.forEach(System.out::print);
System.out.println();
}
Map<Person.Sex, List<String>> namesByGender2 = roster.stream().collect(Collectors.groupingBy((p) -> {
return p.getGender();
}, Collectors.mapping(Person::getName, Collectors.toList())));
Set<Sex> keySet2 = namesByGender2.keySet();
for (Sex sex : keySet2) {
List<String> list = namesByGender2.get(sex);
System.out.println("sex = " + sex);
list.forEach(System.out::print);
System.out.println();
}
}

举例五:Stream.collect方法,分组并求和

@Test
public void test8() {
Map<Person.Sex, Integer> totalAgeByGender = roster.stream().collect(
Collectors.groupingBy(Person::getGender, Collectors.reducing(0, Person::getAge, Integer::sum)));
Set<Sex> keySet2 = totalAgeByGender.keySet();
for (Sex sex : keySet2) {
Integer integer = totalAgeByGender.get(sex);
System.out.println("sex = " + sex);
System.out.println("年龄sum = " + integer); }
}

举例六:Stream.collect方法,分组并计算平均数

 @Test
public void test9() {
Map<Person.Sex, Double> averageAgeByGender = roster.stream()
.collect(Collectors.groupingBy(Person::getGender, Collectors.averagingInt(Person::getAge)));
Set<Sex> keySet2 = averageAgeByGender.keySet();
for (Sex sex : keySet2) {
Double double1 = averageAgeByGender.get(sex);
System.out.println("sex = " + sex);
System.out.println("年龄avg = " + double1);
}
}        

三 并行操作(Parallelism)

llll 

大数据项目2(Java8聚合操作)的更多相关文章

  1. 大数据项目实践:基于hadoop+spark+mongodb+mysql+c#开发医院临床知识库系统

    一.前言 从20世纪90年代数字化医院概念提出到至今的20多年时间,数字化医院(Digital Hospital)在国内各大医院飞速的普及推广发展,并取得骄人成绩.不但有数字化医院管理信息系统(HIS ...

  2. 大数据项目测试<二>项目的测试工作

    大数据的测试工作: 1.模块的单独测试 2.模块间的联调测试 3.系统的性能测试:内存泄露.磁盘占用.计算效率 4.数据验证(核心) 下面对各个模块的测试工作进行单独讲解. 0. 功能测试 1. 性能 ...

  3. 大数据项目之_15_电信客服分析平台_03&04_数据分析

    3.3.数据分析3.3.1.Mysql 表结构设计3.3.2.需求:按照不同的维度统计通话3.3.3.环境准备3.3.4.编写代码:数据分析3.3.5.运行测试3.3.6.bug 解决 3.3.数据分 ...

  4. 大数据项目相关技术栈(Hadoop周边技术)

    J2EE 框架Spring 开发框架 + SSH or SSM Lucene 索引和查询IKAnalyzer 分词Webmagic 爬虫 ETL工具:KettleSqoop 结构化数据库-hadoop ...

  5. Mysql备份系列(3)--innobackupex备份mysql大数据(全量+增量)操作记录

    在日常的linux运维工作中,大数据量备份与还原,始终是个难点.关于mysql的备份和恢复,比较传统的是用mysqldump工具,今天这里推荐另一个备份工具innobackupex.innobacku ...

  6. 如何在IDEA里给大数据项目导入该项目的相关源码(博主推荐)(类似eclipse里同一个workspace下单个子项目存在)(图文详解)

    不多说,直接上干货! 如果在一个界面里,可以是单个项目 注意:本文是以gradle项目的方式来做的! 如何在IDEA里正确导入从Github上下载的Gradle项目(含相关源码)(博主推荐)(图文详解 ...

  7. 大数据项目(MTDAP)随想

    Spark MLlib进行example测试的时候,总是编译不通过,报少包<Spark MLlib NoClassDefFoundError: org/apache/spark/ml/param ...

  8. 大数据项目之_15_电信客服分析平台_01&02_项目背景+项目架构+项目实现+数据生产+数据采集/消费(存储)

    一.项目背景二.项目架构三.项目实现3.1.数据生产3.1.1.数据结构3.1.2.编写代码3.1.3.打包测试3.2.数据采集/消费(存储)3.2.1.数据采集:采集实时产生的数据到 kafka 集 ...

  9. 华为大数据项目fusionInsight

    项目简述:基于开源Hadoop2.0架构的集群网络,进行海量数据的分布式计算.由于Hadoop集群规模不断扩大,而搭建一个同等规模的测试集群需要一笔昂贵的开销.目前有100台左右物料,期望预测计算节点 ...

随机推荐

  1. IntelliJ IDEA使用报错

    GZIPResponseStream不是抽象的, 并且未覆盖javax.servlet.ServletOutputStream中 继承了某个抽象类, 或者 实现某个接口这时候你必须 把基类或接口中的所 ...

  2. Netflix 开源 Polynote:对标 Jupyter,一个笔记本运行多种语言

    谈到数据科学领域的开发工具,Jupyter 无疑是非常知名的一种.它具有灵活高效的特点,非常适合进行开发.调试.分享和教学.近日,Netflix(奈飞)居然也玩起了跨界,他们开源了一个名为 Polyn ...

  3. Oracle数据库索引

    Oracle数据库索引 在关系数据库中,索引是一种与表有关的数据库结构,它可以使对应于表的SQL语句执行得更快.索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容. 对于数据库来说,索 ...

  4. 性能测试:深入理解线程数,并发量,TPS,看这一篇就够了

    并发数,线程数,吞吐量,每秒事务数(TPS)都是性能测试领域非常关键的数据和指标. 那么他们之间究竟是怎样的一个对应关系和内在联系? 测试时,我们经常容易将线程数等同于表述为并发数,这一表述正确吗? ...

  5. 菜鸟系列Fabric源码学习 — peer节点启动

    Fabric 1.4 源码分析peer节点启动 peer模块采用cobra库来实现cli命令. Cobra提供简单的接口来创建强大的现代化CLI接口,比如git与go工具.Cobra同时也是一个程序, ...

  6. Sql 修改表结构

    添加字段 alter table 表名 add 字段名 nvarchar(100) not null 修改字段 alter table 表名 alter column 字段名 int not null ...

  7. Flask入门学习——蓝图Blueprint

    flask蓝图可以实现应用程序的模块化,即通常作用于相同的url前缀,eg:/user/id,/user/profile等类似这样,可以放在一个模块当中,这样会让应用更加清晰便于开发与维护. 这里有个 ...

  8. C程序设计风格

    问:如何在源文件中合理分配函数? 答:通常,相关的函数放在同一个文件中.有时候(例如开发库的时候),一个源文件(自然也 就是一个目标文件)放一个函数比较合适.有时候,尤其是对某些程序员,太多的源文件可 ...

  9. 线程池&进程池

    线程池&进程池 池子解决什么问题? 1.创建/销毁线程伴随着系统开销,如果过于频繁会影响系统运行效率 2.线程并发数量过多,抢占系统资源,从而导致系统阻塞甚至死机 3.能够刚好的控制和管理池子 ...

  10. 关于小码哥kylin

    技术格言: 用双手改变人生,用代码改变世界! 个人网站:http://www.isainttech.com QQ:56619556 Email:dragonsaint@qq.com 微信:kylin1 ...