Java8的lambda表达式学习记录—lambda表达式Stream流学习八、久—Stream的中间操作 : 查找与匹配、归约与收集、分组
一,查找与匹配
Stream流的终止操作,以下操作都是Stream.
调用:
allMatch
——检查是否匹配所有元素,返回值为booleananyMatch
——检查是否至少匹配一个元素,返回值为booleannoneMatch
——检查是否没有匹配的元素,返回值为booleanfindFirst
——返回第一个元素,返回值为Optional集合findAny
——返回当前流中的任意元素,返回值为Optionalcount
——返回流中元素的总个数,返回值为Longmax
——返回流中的最大值,返回值为Optionalmin
——返回流中的最小值,返回值为Optional
//Employee对象新增枚举类型
public class Employee {
private status status;
public enum status{
FREE,
BUSY,
VOCATION;
}
}
@Test
public void test1(){
List<Employee> list = Arrays.asList(
new Employee("张三", 18, 9999.99, Employee.status.FREE),//枚举类型
new Employee("李四", 20, 7777.77, Employee.status.BUSY),
new Employee("王五", 36, 5555.55, Employee.status.VOCATION),
new Employee("赵六", 50, 3333.33, Employee.status.FREE),
new Employee("田七", 10, 2222.22, Employee.status.VOCATION)
);
Boolean b1 = list.stream().allMatch((e) -> e.getStatus().equals(Employee.status.BUSY));//.allMatch匹配所有
System.out.println(b1);//是否所有的都和BUSY相等, false
Boolean b2 = list.stream().anyMatch(e -> e.getStatus().equals(Employee.status.BUSY));//.anyMatch匹配至少一个
System.out.println(b2);//至少有一个和BUSY相等, true
Boolean b3 = list.stream().noneMatch(e -> "花招虫".equals(e.getName()));//.noneMatch是否没有匹配的元素
System.out.println(b3);//没有值与之相匹配, true
Optional<Employee> op = list.stream().sorted(Comparator.comparingDouble(Employee::getSalary)).findFirst();//.findFirst返回第一个元素
System.out.println(op);//Optional[Employee{name='田七', age=10, salary=2222.22, status=VOCATION}]
/*
Optional 是Java8中新推出的用来避免空指针异常的函数型接口,它会自动将可能为空的值放入里面,然后做处理.
*/
Optional<Employee> op2 = list.stream().filter(e -> Employee.status.FREE.equals(e.getStatus())).findAny();//.findAny在当前流中随机返回一个元素
System.out.println(op2);//Optional[Employee{name='张三', age=18, salary=9999.99, status=FREE}]
long l = list.stream().count();
System.out.println(l);//5
Optional<Employee> op3 = list.stream().max(Comparator.comparingDouble(Employee::getSalary));//.max查找流中最大元素值
System.out.println(op3);//Optional[Employee{name='张三', age=18, salary=9999.99, status=FREE}]
}
//练习题 : 1)查出list集合中工资最多的人的信息 2)求集合中最大工资是多少
public void test2(){
Optional<Employee> op = list.stream().sorted(Comparator.comparingDouble(Employee::getSalary)).findFirst();
System.out.println(op);//Optional[Employee{name='田七', age=10, salary=2222.22, status=VOCATION}]
Optional<Double> op2 = list.stream().map(Employee::getSalary).max(Double::compareTo);
System.out.println(op2);//Optional[9999.99]
}
二,归约与收集
//新建测试集合
List<Employee> emps = Arrays.asList(
new Employee("张三", 18, 9999.99, Employee.status.FREE),//枚举类型
new Employee("李四", 20, 7777.77, Employee.status.BUSY),
new Employee("王五", 36, 5555.55, Employee.status.VOCATION),
new Employee("赵六", 50, 3333.33, Employee.status.FREE),
new Employee("田七", 10, 2222.22, Employee.status.VOCATION)
);
归约 : reduce(T identity, BinaryOperator) / reduce(BinaryOperator)
——可以将流中的元素反复结合起来,做指定的操作,得到一个值。
@Test
public void test1(){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = list.stream().reduce(0, (x, y) -> x+y);//0是x的起始值,y的起始值是1,因为给了起始值,所以必然不为空,不需要用Optional封装
System.out.println(sum);
//求所有人的工资总和
Optional<Double> d = emps.stream().map(Employee::getSalary).reduce(Double::sum);//Double::sum JDK1.8新增的静态方法,计算两个double类型的值
//因为没有指定起始值,java判断d可能为空,所以封装了Optional<>
System.out.println(d);
}
收集 : Stream.collect
——将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素汇总的方法。
@Test
public void test2(){
List<String> l1 = emps.stream().map(Employee::getName).collect(Collectors.toList());
System.out.println(l1);
HashSet<String> set = emps.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
//Collectors.toCollection(Supplier<T>) 可以转换为任意集合
set.forEach(System.out::println);
}
//收集的方法求总数、平均值、总和、最大值、最小值
@Test
public void test3(){
System.out.println(emps.stream().collect(Collectors.counting()));//总数
System.out.println(emps.stream().collect(Collectors.averagingDouble(Employee::getSalary)));//平均值
System.out.println(emps.stream().collect(Collectors.summingDouble(Employee::getSalary)));//总和
Optional<Employee> max = emps.stream().collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(max.get());
Optional<Double> min = emps.stream().map(Employee::getSalary).collect(Collectors.minBy(Double::compare));
System.out.println(min.get());
}
三,分组与分区
分组函数 : Stream.collect(Collectors.groupingBy())
,可以传两个参数进行多条件分组
@Test
public void test4(){
Map<Employee.status, List<Employee>> map = emps.stream().collect(Collectors.groupingBy(Employee::getStatus));//groupingBy分组函数
System.out.println(map);
//多条件分组,先按status分组,然后再按年龄分组
Map<Employee.status, Map<String, List<Employee>>> map2 = emps.stream().collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy(e -> {
if (e.getAge() <= 35){
return "青年";
}else if (e.getAge() <= 50){
return "中年";
}else{
return "老年";
}
})));
System.out.println(map2);
}
//{FREE=[Employee{name='张三', age=18, salary=9999.99, status=FREE}, Employee{name='赵六', age=50, salary=3333.33, status=FREE}], VOCATION=[Employee{name='王五', age=36, salary=5555.55, status=VOCATION}, Employee{name='田七', age=10, salary=2222.22, status=VOCATION}], BUSY=[Employee{name='李四', age=20, salary=7777.77, status=BUSY}]}
//{FREE={青年=[Employee{name='张三', age=18, salary=9999.99, status=FREE}], 中年=[Employee{name='赵六', age=50, salary=3333.33, status=FREE}]}, VOCATION={青年=[Employee{name='田七', age=10, salary=2222.22, status=VOCATION}], 中年=[Employee{name='王五', age=36, salary=5555.55, status=VOCATION}]}, BUSY={青年=[Employee{name='李四', age=20, salary=7777.77, status=BUSY}]}}
分区函数 : Stream.collect(Collectors.partitioningBy())
,根据参数进行分组,参数返回值为boolean
@Test
public void test5(){
Map<Boolean, List<Employee>> map = emps.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > 5000));
System.out.println(map);
}
//{false=[Employee{name='赵六', age=50, salary=3333.33, status=FREE}, Employee{name='田七', age=10, salary=2222.22, status=VOCATION}], true=[Employee{name='张三', age=18, salary=9999.99, status=FREE}, Employee{name='李四', age=20, salary=7777.77, status=BUSY}, Employee{name='王五', age=36, salary=5555.55, status=VOCATION}]}
四,collect的其他操作
获取数据处理对象 : stream.collect(Collectors.summarizingDouble())
,该对象可以直接拿来求最大最小值,平均数。
@Test
public void test6(){
DoubleSummaryStatistics b = emps.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(b.getMax());
System.out.println(b.getMin());
System.out.println(b.getAverage());
}
拼接字符串 : stream.map().collect(Collectors.joining())
,可以直接拼接流中指定的元素,可指定凭借符号,一个参数时为拼接符号,三个参数为拼接符号、起始值、结束值。
@Test
public void test7(){
String names = emps.stream().map(Employee::getName).collect(Collectors.joining(",", "姓名:", "。"));
System.out.println(names);
}