JDK1.8新特性

Java Stream API

//合并城市区域名称
String cityNames = value.stream().map(x -> x.getCityName() + (x.getDistrictName() == null ? “” : x.getDistrictName())).collect(Collectors.joining(“,”));

参考:https://blog.csdn.net/weixin_44391036/article/details/106102332
1.1Stream
可以提高我们处理集合类数据的效率。他就像一个流水线,在这条流水线上有很多工作人员来操作他的数据,A处理完流到B,B处理完流到C。。。在没有学这个之前,我们处理集合类型的数据通常通过for循环,一层一层,一次一次,Stream 会显的更加简洁,方便。

操作步骤:
把产品放到流水线上(转化为流),称为源操作
对产品进行操作,例如包上包装袋(过滤,数据转换等等),称为中间操作
流水线到底了,给他拿纸箱装起来(转换为其他类型返回),称为终端操作
工作人员:Filter(过滤)、Map(映射)、sort(排序),distinct(去重)等等

List<String> strs = ArrayList.asList("one","two","three","four","five");
// Stream操作
List<String> newStrs = strs.stream()
    .filter(s -> s.startsWith("t"))
    .map(String::toUpperCase)
    .sorted()
    .collect(toList());
System.out.println(newStrs);

使用stream()将集合类型数据转化为流水线。
filter() 工作人员过滤出 “t” 开头的数据,剩下的不要,拿到流水线外。
map() 工作人员将剩下的每个数据转化为大写。
sorted() 工作人员给剩下的数据排序。
collect() 工作人员使用函数toList() 将剩下的数据转换为一个新的List并返回。
所以,输出结果应该是 : [ TWO , THREE ]

2.1 各类型转化为流
数组使用Stream.of() 方法
集合使用集合类对象的stream()方法
文本文件使用Files.lines()方法
示例:

//数组
String[] arr = {"one","two","three","four","five"};
Stream<String> arrStream = Stream.of(arr);

Stream<String> arrStream = Stream.of("one","two","three","four","five");
//集合类
List<String> list = ArrayList.asList("one","two","three","four","five");
Stream<String> listStream = list.stream();
//文本文件
Stream<String> txtStream = Files.lines(Paths.get("demo.txt"));

2.2 filter
作用?
在上面草率的示例中可以看出来,filter这个工作人员的职责是过滤出符合要求的数据。

详细示例(应用到操作对象):
实体类 Employee.java (使用了lombok)

@Data
@AllArgsConstructor
public class Employee{
    private Integer id; 
    private Integer age;
    private String sex;			//性别
    private String firstName;	
    private String lastName;
}

测试类 StreamFilterTest.java

public class StreamFilterTest{
    //新建10个员工对象(后面的示例也基本都会用到这10个员工)
    public static void main(String[] args){
        Employee e1 = new Employee(1,23,"M","Rick","Beethovan");
        Employee e2 = new Employee(2,13,"F","Martina","Hengis");
        Employee e3 = new Employee(3,43,"M","Ricky","Martin");
        Employee e4 = new Employee(4,26,"M","Jon","Lowman");
        Employee e5 = new Employee(5,19,"F","Cristine","Maria");
        Employee e6 = new Employee(6,15,"M","David","Feezor");
        Employee e7 = new Employee(7,68,"F","Melissa","Roy");
        Employee e8 = new Employee(8,79,"M","Alex","Gussin");
        Employee e9 = new Employee(9,15,"F","Neetu","Singh");
        Employee e10 = new Employee(10,45,"M","Naveen","Jain");
        
        List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
        List<Employee> filterEs = employees.stream()
            .filter(e -> e.getAge() > 70 && "M".equals(e.getSex()))
            .collect(Collectors.toList());
        System.out.println(filterEs);
    }
}

filter传入的lambda表达式的意思是筛选出年龄大于70且性别为男性的员工。
所以,输出:[Employee(id=8, age=79, gender=M, firstName=Alex, lastName=Gussin)]

filter 入参类型为 Predicate<? super T>,所以如果复用较多的话,可以抽象出来
例如:寻找年龄大于70和性别为男这两个条件

public static Predicate<Employee> ageMore70 = x -> x.getAge() > 70;
public static Predicate<Employee> sexM = x -> "M".equals(x.getSex());
filter中的参数可以如SQL的where一般只有组合
// and 寻找年龄大于70 且 性别为男的员工
.filter(Empolyee.ageMore70 and Empolyee.sexM)
// or 寻找年龄大于70 或者 性别为男的员工
.filter(Empolyee.ageMore70) or Empolyee.sexM)    
// negate(相反) 寻找性别不为男的员工 0.0
.filter(Empolyee.sexM.negate())   

2.2 map
作用?
对流水线上的每一个数据进行转换操作。
示例:(将所有数据转换为大写)

List<String> strs = Stream.of("a","b","c","d")
    .map(String::toUperCase)
    .collect(Collectors.toList());
// 等价于
List<String> strs = Stream.of("a","b","c","d")
    .map(s -> s.toUpperCase())
    .collect(Collectors.toList());

// 复杂点 类型转换
List<Integer> ins = Stream.of("a","b","c","d")
    .map(String::length)
    .collect(Collectors.toList());
System.out.println(ins); // 输出 1,1,1,1
// 也可以这样
Stream.of("a","b","c","d")
    .mapToInt(String::length) //除了mapToInt 还有maoToLong,mapToDouble等等
    .forEach(System.out::println);
// 再复杂点 对象类型转换
// 还是前面那10个员工对象,过年了,大家都长了一岁,且性别互换
List<Employee> eys = employees.stream
    .peek(e -> { //peek()是一种特殊的map,当没有返回值,或者参数就是返回值的时候可以用peek()
        e.setAge(e.getAge() + 1);
        e.setSex("M".equals(e.getSex)?"F":"M")
    }).collect(Collectors.toList());
System.out.println(eys);

// 除此之外 还有flatMap可以用于操作子流水线
List<String> words = Arrays.asList("hello", "word");
words.stream()
        .flatMap(w -> Arrays.stream(w.split("")))    //[h,e,l,l,o,w,o,r,l,d]
        .forEach(System.out::println);

2.3 distinct , limit , skip
怎么三个一起来了?太草率了吧!这些都是做什么的?
字面意思。。。
distinct作用是去重,调用的是equals方法做比较,如果需要自定义,可以重写equals方法。
limit传入一个整数n,截取[0 , n] 个数据。
skip传入一个整数n, 跳过n个数据后截取到最后。
示例:

// limit
Stream.of("a","b","c","d").limit(2).forEach(System.out::println); //输出 a,b
// skip
Stream.of("a","b","c","d").skip(2).forEach(System.out::println); //输出 c,d
// distinct
Stream.of("a","b","b","d").distinct(2).forEach(System.out::println); //输出 a,b,d

2.4 sort
作用?
排序,就是这么个作用,可以幻想一个业务场景,就比如前面的10个员工对象,我现在要按照年龄大小排序,用sort的话4行代码就可以搞定了。
先看字符串的排序:

// london是小写的奥
List<String> cities = Arrays.asList(
        "Milan",
        "london",
        "San Francisco",
        "Tokyo",
        "New Delhi"
);
System.out.println(cities);
//[Milan, london, San Francisco, Tokyo, New Delhi]

cities.sort(String.CASE_INSENSITIVE_ORDER);
System.out.println(cities);
//[london, Milan, New Delhi, San Francisco, Tokyo]

cities.sort(Comparator.naturalOrder());
System.out.println(cities);
//[Milan, New Delhi, San Francisco, Tokyo, london]

String.CASE_INSENSITIVE_ORDER 大小写不敏感
Comparator.naturalOrder() 自然排序
整数型排序:

List<Integer> numbers = Arrays.asList(6, 2, 1, 4, 9);
System.out.println(numbers); //[6, 2, 1, 4, 9]

numbers.sort(Comparator.naturalOrder());  //自然排序
System.out.println(numbers); //[1, 2, 4, 6, 9]

numbers.sort(Comparator.reverseOrder()); //倒序排序
System.out.println(numbers);  //[9, 6, 4, 2, 1]

Comparator.reverseOrder() 降序排列
按对象的某个属性进行排列:
// 还是前面那10个员工 按年龄排序

List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);

employees.sort(Comparator.comparing(Employee::getAge)); //升序
employees.forEach(System.out::println);

employees.sort(Comparator.comparing(Employee::getAge).reversed()); //降序

也可以使用Comparator链进行组合排序

// 先按年龄降序,再按性别升序 都是倒序的话 把reversed()加在最后
employees.sort(
        Comparator.comparing(Employee::getAge).reversed()
        .thenComparing(Employee::getSex)
);
employees.forEach(System.out::println);

自定义Comparator排序规则
/**

  • 使用匿名类的方式实现Comparator的唯一抽象方法compare
  • 小于返回-1 等于返回0 大于返回1
    */

//java8之前的写法

employees.sort(new Comparator<Employee>() {
    @Override
    public int compare(Employee em1, Employee em2){
        if(em1.getAge() == em2.getAge()){
            return 0;
        }
        return em1.getAge() - em2.getAge() > 0 ? -1:1;
    }
});
//lambda表达式
employees.sort((em1,em2) -> {
    if(em1.getAge() == em2.getAge()){
            return 0;
        }
        return em1.getAge() - em2.getAge() > 0 ? 1:-1;
});

2.5 匹配和查找元素
日常业务中,我们可能会有以下逻辑:
是否包含某一个“匹配规则”的元素
是否所有的元素都符合某一个“匹配规则”
是否所有元素都不符合某一个“匹配规则”
查找第一个符合“匹配规则”的元素
查找任意一个符合“匹配规则”的元素
如果用for循环写,条件也多,人容易裂开。。。

如果使用Stream:
// 对 又是前面那10个员工
// 是否包含有超过70岁的员工

// 之前抽象出来的谓词逻辑

boolean isHaveMore70 = employees.stream().anyMatch(Employee.ageMore70);
// 使用lambda表达式
boolean isHaveMore70 = employees.stream().anyMatch(e -> e.getAge() > 70);

anyMatch() 是否包含某一个“匹配规则”的元素
allMatch() 是否所有的元素都符合某一个“匹配规则”
noneMatch() 是否所有元素都不符合某一个“匹配规则”
findFirst() 查找第一个符合“匹配规则”的元素

写法:

Optional<Employee> employeeOptional
        =  employees.stream().filter(e -> e.getAge() > 40).findFirst();
System.out.println(employeeOptional.get());

findAny() 查找任意一个符合“匹配规则”的元素 和findFirst用法相同

关于Optional
Optional类代表一个值存在或者不存在。在java8中引入,这样就不用返回null了。
isPresent() 将在 Optional 包含值的时候返回 true , 否则返回 false 。
ifPresent(Consumer block) 会在值存在的时候执行给定的代码块。我们在第3章
介绍了 Consumer 函数式接口;它让你传递一个接收 T 类型参数,并返回 void 的Lambda
表达式。
T get() 会在值存在时返回值,否则?出一个 NoSuchElement 异常。
T orElse(T other) 会在值存在时返回值,否则返回一个默认值。
2.6 归约操作 reduce

介绍一下?
reduce函数有三个参数:

Identity标识:一个元素,它是归约操作的初始值,如果流为空,则为默认结果。

Accumulator累加器:具有两个参数的函数:归约运算的部分结果和流的下一个元素。

Combiner合并器(可选):当归约并行化时,或当累加器参数的类型与累加器实现的类型不匹配时,用于合并归约操作的部分结果的函数。

阶段累加结果作为累加器的第一个参数

集合遍历元素作为累加器的第二个参数

Integer类型
reduce初始值为0,累加器可以是lambda表达式,也可以是方法引用。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
int result = numbers
        .stream()
        .reduce(0, (subtotal, element) -> subtotal + element);
System.out.println(result);  //21

int result = numbers
        .stream()
        .reduce(0, Integer::sum);
System.out.println(result); //21

String类型
不仅可以归约Integer类型,只要累加器参数类型能够匹配,可以对任何类型的集合进行归约计算。

List<String> letters = Arrays.asList("a", "b", "c", "d", "e");
String result = letters
        .stream()
        .reduce("", (partialString, element) -> partialString + element);
System.out.println(result);  //abcde


String result = letters
        .stream()
        .reduce("", String::concat);
System.out.println(result);  //ancde

对象类型
计算所有员工的年龄总和

Integer total = employees.stream().map(Employee::getAge).reduce(0,Integer::sum);
System.out.println(total); //346

先由map将员工对象类型转换为年龄(Integer)
再对Integer进行归约

2.7 终端操作
回想一下
前面的Stream的示例尾端,出现过两种:
一个是forEach,字面意思也就是循环遍历的;
另一个是collect,这个就是收集的意思。

示例:
// 收集到Set
.collect(Collectors.toSet());
// 收集到List
.collect(Collectors.toList());
// 通用收集
.collect(Collectors.toCollection(LinkedList::new));
.collect(Collectors.toCollection(PriorityQueue::new));
// 收集到数组
.toArray(String[]::new);
//收集到Map
.distinct()
.collect(Collectors.toMap(
       Function.identity(),   //元素输入就是输出,作为key
       s -> (int) s.chars().distinct().count()// 输入元素的不同的字母个数,作为value
));
// 分组收集
.collect(Collectors.groupingBy(
       s -> s.charAt(0) ,  //根据元素首字母分组,相同的在一组
       // counting()        // 加上这一行代码可以实现分组统计
));

2.8 其他的一些可能会用到的方法

boolean containsTwo = IntStream.of(1, 2, 3).anyMatch(i -> i == 2);
// 判断管道中是否包含2,结果是: true

long nrOfAnimals = Stream.of(
    "Monkey", "Lion", "Giraffe", "Lemur"
).count();
// 管道中元素数据总计结果nrOfAnimals: 4

int sum = IntStream.of(1, 2, 3).sum();
// 管道中元素数据累加结果sum: 6

OptionalDouble average = IntStream.of(1, 2, 3).average();
//管道中元素数据平均值average: OptionalDouble[2.0]

int max = IntStream.of(1, 2, 3).max().orElse(0);
//管道中元素数据最大值max: 3

IntSummaryStatistics statistics = IntStream.of(1, 2, 3).summaryStatistics();
// 全面的统计结果statistics: IntSummaryStatistics{count=3, sum=6, min=1, average=2.000000, max=3}

以上,就是我当前阶段对于java8的一些认识,应该算是初步掌握了lambda表达式及Stream的基础用法,像Stream的话以上的示例全部都是针对串行,他其实还有并行的操作,根据大佬们的研究,Stream的并行效率是远高于之前的for循环的,但是由于时间的关系,我当前阶段就先学到这吧。

Java8使用Stream流实现List列表的查询、统计、排序、分组:

(1)map(T -> R) 和 flatMap(T -> Stream)
使用 map() 将流中的每一个元素 T 映射为 R(类似类型转换)。
使用 flatMap() 将流中的每一个元素 T 映射为一个流,再把每一个流连接成为一个流。

//获取用户列表
List<User> userList = UserService.getUserList();
//获取用户名称列表
List<String> nameList = userList.stream().map(User::getName).collect(Collectors.toList());
//或者:List<String> nameList = userList.stream().map(user -> user.getName()).collect(Collectors.toList());
//遍历名称列表
nameList.forEach(System.out::println);
 返回的结果为数组类型,写法如下:
//数组类型
String[] nameArray = userList.stream().map(User::getName).collect(Collectors.toList()).toArray(new String[userList.size()]);

【示例】使用 flatMap() 将流中的每一个元素连接成为一个流。

/**
* 使用flatMap()将流中的每一个元素连接成为一个流
*/
//创建城市 
List<String> cityList = new ArrayList<String>();
cityList.add("北京;上海;深圳;");
cityList.add("广州;武汉;杭州;");
//分隔城市列表,使用 flatMap() 将流中的每一个元素连接成为一个流。
cityList = cityList.stream()
.map(city -> city.split(";"))
.flatMap(Arrays::stream)
.collect(Collectors.toList());
//遍历城市列表
cityList.forEach(System.out::println);
}

(2)统计方法
2.1 reduce((T, T) -> T) 和 reduce(T, (T, T) -> T)
使用 reduce((T, T) -> T) 和 reduce(T, (T, T) -> T) 用于组合流中的元素,如求和,求积,求最大值等。
【示例】使用 reduce() 求用户列表中年龄的最大值、最小值、总和。

/**
* 使用 reduce() 方法
*/
//获取用户列表
List<User> userList = UserService.getUserList();
//用户列表中年龄的最大值、最小值、总和
int maxVal = userList.stream().map(User::getAge).reduce(Integer::max).get();
int minVal = userList.stream().map(User::getAge).reduce(Integer::min).get();
int sumVal = userList.stream().map(User::getAge).reduce(0,Integer::sum);
//打印结果
System.out.println("最大年龄:" + maxVal);
System.out.println("最小年龄:" + minVal);
System.out.println("年龄总和:" + sumVal);
}

2.2 mapToInt(T -> int) 、mapToDouble(T -> double) 、mapToLong(T -> long)
int sumVal = userList.stream().map(User::getAge).reduce(0,Integer::sum);计算元素总和的方法其中暗含了装箱成本,map(User::getAge) 方法过后流变成了 Stream 类型,而每个 Integer 都要拆箱成一个原始类型再进行 sum 方法求和,这样大大影响了效率。针对这个问题 Java 8 有良心地引入了数值流 IntStream, DoubleStream, LongStream,这种流中的元素都是原始数据类型,分别是 int,double,long。

流转换为数值流:
mapToInt(T -> int) : return IntStream
mapToDouble(T -> double) : return DoubleStream
mapToLong(T -> long) : return LongStream
【示例】使用 mapToInt() 求用户列表中年龄的最大值、最小值、总和、平均值。

/**
* 使用 mapToInt() 方法
*/
//获取用户列表
List<User> userList = UserService.getUserList();
//用户列表中年龄的最大值、最小值、总和、平均值
int maxVal = userList.stream().mapToInt(User::getAge).max().getAsInt();
int minVal = userList.stream().mapToInt(User::getAge).min().getAsInt();
int sumVal = userList.stream().mapToInt(User::getAge).sum();
double aveVal = userList.stream().mapToInt(User::getAge).average().getAsDouble();
//打印结果
System.out.println("最大年龄:" + maxVal);
System.out.println("最小年龄:" + minVal);
System.out.println("年龄总和:" + sumVal);
System.out.println("平均年龄:" + aveVal);

2.3 counting() 和 count()
使用 counting() 和 count() 可以对列表数据进行统计。
【示例】使用 count() 统计用户列表信息。

/**
* 使用 counting() 或 count() 统计
*/
//获取用户列表
List<User> userList = UserService.getUserList();
//统计研发部的人数,使用 counting()方法进行统计
Long departCount = userList.stream().filter(user -> user.getDepartment() == "研发部").collect(Collectors.counting());
//统计30岁以上的人数,使用 count()方法进行统计(推荐)
Long ageCount = userList.stream().filter(user -> user.getAge() >= 30).count();
//统计薪资大于1500元的人数
Long salaryCount = userList.stream().filter(user -> user.getSalary().compareTo(BigDecimal.valueOf(1500)) == 1).count();
//打印结果
System.out.println("研发部的人数:" + departCount + "人");
System.out.println("30岁以上的人数:" + ageCount + "人");
System.out.println("薪资大于1500元的人数:" + salaryCount + "人");

2.4 summingInt()、summingLong()、summingDouble()
用于计算总和,需要一个函数参数。

//计算年龄总和
int sumAge = userList.stream().collect(Collectors.summingInt(User::getAge));

2.5 averagingInt()、averagingLong()、averagingDouble()
用于计算平均值。

//计算平均年龄
double aveAge = userList.stream().collect(Collectors.averagingDouble(User::getAge));

2.6 summarizingInt()、summarizingLong()、summarizingDouble()
这三个方法比较特殊,比如 summarizingInt 会返回 IntSummaryStatistics 类型。
IntSummaryStatistics类提供了用于计算的平均值、总数、最大值、最小值、总和等方法
【示例】使用 IntSummaryStatistics 统计:最大值、最小值、总和、平均值、总数。

/**
* 使用 summarizingInt 统计
*/
//获取用户列表
List<User> userList = UserService.getUserList();
//获取IntSummaryStatistics对象
IntSummaryStatistics ageStatistics = userList.stream().collect(Collectors.summarizingInt(User::getAge));
//统计:最大值、最小值、总和、平均值、总数
System.out.println("最大年龄:" + ageStatistics.getMax());
System.out.println("最小年龄:" + ageStatistics.getMin());
System.out.println("年龄总和:" + ageStatistics.getSum());
System.out.println("平均年龄:" + ageStatistics.getAverage());
System.out.println("员工总数:" + ageStatistics.getCount());

2.7 BigDecimal类型的统计
对于资金相关的字段,通常会使用BigDecimal数据类型。
【示例】统计用户薪资信息。

/**
* BigDecimal类型的统计
*/
//获取用户列表
List<User> userList = UserService.getUserList();
//最高薪资
BigDecimal maxSalary = userList.stream().map(User::getSalary).max((x1, x2) -> x1.compareTo(x2)).get();
//最低薪资
BigDecimal minSalary = userList.stream().map(User::getSalary).min((x1, x2) -> x1.compareTo(x2)).get();
//薪资总和
BigDecimal sumSalary = userList.stream().map(User::getSalary).reduce(BigDecimal.ZERO, BigDecimal::add);
//平均薪资
BigDecimal avgSalary = userList.stream().map(User::getSalary).reduce(BigDecimal.ZERO, BigDecimal::add).divide(BigDecimal.valueOf(userList.size()), 2, BigDecimal.ROUND_HALF_UP);
//打印统计结果
System.out.println("最高薪资:" + maxSalary + "元");
System.out.println("最低薪资:" + minSalary + "元");
System.out.println("薪资总和:" + sumSalary + "元");
System.out.println("平均薪资:" + avgSalary + "元");

(3)排序方法
3.1 sorted() / sorted((T, T) -> int)
如果流中的元素的类实现了 Comparable 接口,即有自己的排序规则,那么可以直接调用 sorted() 方法对元素进行排序,如 Stream。反之, 需要调用 sorted((T, T) -> int) 实现 Comparator 接口。
【示例】根据用户年龄进行排序。

/**
* 使用 sorted() 排序
*/
//获取用户列表
List<User> userList = UserService.getUserList();
//根据年龄排序(升序)
userList = userList.stream().sorted((u1, u2) -> u1.getAge() - u2.getAge()).collect(Collectors.toList());
//推荐:userList = userList.stream().sorted(Comparator.comparingInt(User::getAge)).collect(Collectors.toList());
//降序:userList = userList.stream().sorted(Comparator.comparingInt(User::getAge).reversed()).collect(Collectors.toList());
//遍历用户列表 
userList.forEach(System.out::println);
 
推荐使用如下写法:
//升序
userList = userList.stream().sorted(Comparator.comparingInt(User::getAge)).collect(Collectors.toList());
//降序
userList = userList.stream().sorted(Comparator.comparingInt(User::getAge).reversed()).collect(Collectors.toList());

3.2、分组方法
groupingBy
使用 groupingBy() 将数据进行分组,最终返回一个 Map 类型。
【示例】根据部门对用户列表进行分组。

/**
* 使用 groupingBy() 分组
*/
//获取用户列表
List<User> userList = UserService.getUserList(); 
//根据部门对用户列表进行分组
Map<String,List<User>> userMap = userList.stream().collect(Collectors.groupingBy(User::getDepartment));
//遍历分组后的结果
userMap.forEach((key, value) -> {
System.out.println(key + ":");
value.forEach(System.out::println);
System.out.println("--------------------------------------------------------------------------");
});

多级分组
groupingBy 可以接受一个第二参数实现多级分组。
【示例】根据部门和性别对用户列表进行分组。

/**
* 使用 groupingBy() 多级分组
*/
//获取用户列表
List<User> userList = UserService.getUserList();
//根据部门和性别对用户列表进行分组
Map<String,Map<String,List<User>>> userMap = userList.stream()
.collect(Collectors.groupingBy(User::getDepartment,Collectors.groupingBy(User::getSex)));
//遍历分组后的结果
userMap.forEach((key1, map) -> {
System.out.println(key1 + ":");
map.forEach((key2,user)->
{
System.out.println(key2 + ":");
user.forEach(System.out::println);
});
System.out.println("--------------------------------------------------------------------------");
});

分组汇总
【示例】根据部门进行分组,汇总各个部门用户的平均年龄。

/**
* 使用 groupingBy() 分组汇总
*/
//获取用户列表
List<User> userList = UserService.getUserList();
//根据部门进行分组,汇总各个部门用户的平均年龄
Map<String, Double> userMap = userList.stream().collect(Collectors.groupingBy(User::getDepartment, Collectors.averagingInt(User::getAge)));
//遍历分组后的结果
userMap.forEach((key, value) -> {
System.out.println(key + "的平均年龄:" + value);
});

参考:http://t.zoukankan.com/shoshana-kong-p-14406683.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值