提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
1.stream 收集
Collectors工具类
注意区分 Collections工具类
练习1:查找工资大于6000的员工,结果返回为一个List
@Test
public void test02() {
List<Employee> list = new ArrayList<>();
list.add(new Employee(1001, "马化腾", 34, 6000.38));
list.add(new Employee(1002, "马云", 12, 9876.12));
list.add(new Employee(1003, "刘强东", 33, 3000.82));
list.add(new Employee(1004, "雷军", 26, 7657.37));
list.add(new Employee(1005, "李彦宏", 65, 5555.32));
list.add(new Employee(1006, "比尔盖茨", 42, 9500.43));
list.add(new Employee(1007, "任正非", 26, 4333.32));
list.add(new Employee(1008, "扎克伯格", 35, 2500.32));
List<Employee> employeeList = list.stream().filter(e ->
e.getSalary() > 6000).collect(Collectors.toList());
employeeList.forEach(System.out::println);
}
练习2:查找年龄小于40的员工,结果返回为一个set
@Test
public void test02() {
List<Employee> list = new ArrayList<>();
list.add(new Employee(1001, "马化腾", 34, 6000.38));
list.add(new Employee(1002, "马云", 12, 9876.12));
list.add(new Employee(1003, "刘强东", 33, 3000.82));
list.add(new Employee(1004, "雷军", 26, 7657.37));
list.add(new Employee(1005, "李彦宏", 65, 5555.32));
list.add(new Employee(1006, "比尔盖茨", 42, 9500.43));
list.add(new Employee(1007, "任正非", 26, 4333.32));
list.add(new Employee(1008, "扎克伯格", 35, 2500.32));
Set<Employee> employeeSet = list.stream().filter(employee ->
employee.getAge() < 40
).collect(Collectors.toSet());
employeeSet.forEach(System.out::println);
}
练习2:Collectors.toMap
package com.cy.month11;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class Test05 {
public static void main(String[] args) {
List<Employee> list = Arrays.asList(new Employee("1","张三"),
new Employee("2","李四"),
new Employee("3","王五"));
Map<String, String> map = list.stream().collect(Collectors.toMap(Employee::getId, Employee::getName));
System.out.println(map.toString());
}
private static class Employee {
String id;
String name;
public Employee(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
(v1, v2) -> v2
- (v1, v2) -> v2 表示如果有相同的key,则使用后面的值覆盖key已经有的值。
- 如果(v1, v2) ->v1, 则不覆盖,保留key已经有的值。
Map相同的key只能有一个。(注意:如果不指定覆盖策略,遇到相同key会抛异常)
案例
public static void main(String[] args) {
List<Person> personList =new ArrayList<>();
personList.add(new Person("于问问","988"));
personList.add(new Person("苗问问","988"));
personList.add(new Person("李问问","777"));
Map<String, String> personMap = personList.stream()
.collect(
Collectors.toMap(Person::getCode, Person::getName)
);
}
这样会不会有问题?答案是会有问题的。
Map的key值不能重复,现在于问问和苗问问的code号都是988
遇到这种情况转Map时就必须得有取舍了,苗问问和于问问只能留一个,那就留苗问问吧
Map<String, String> personMap = personList.stream()
.collect(Collectors.toMap(Person::getCode, Person::getName, (v1, v2) -> v2));
2.Collectors.groupingBy
@Data
@AllArgsConstructor
public class Student {
String name ;
int age;
String clazz ;
String course ;c
int score;
}
1. 基础分组功能 (3种写法一样效果)
- 说明:基础功能,分组并返回Map容器。将用户自定义的元素作为键,同时将键相同的元素存放在List中作为值。
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class test {
public static void main(String[] args) {
List<Student> students = Stream.of(
new Student("张三", 16, "高一1班", "语文", 88),
new Student("李四", 17, "高一2班", "数学", 90),
new Student("王五", 18, "高一3班", "外语", 100)
).collect(Collectors.toList());
// 方法1 :将不同课程的学生进行分类
Map<String, List<Student>> groupByCourse = students.stream().collect(Collectors.groupingBy(Student::getCourse));
System.out.println(groupByCourse);
// 方法2 :上面的方法中容器类型和值类型都是默认指定的,容器类型为:HashMap,值类型为:ArrayList
Map<String, List<Student>> groupByCourse1 = students.stream().collect(Collectors.groupingBy(Student::getCourse, Collectors.toList()));
System.out.println(groupByCourse1);
// 方法3 : 可以通过下面的方法自定义返回结果、值的类型
Map<String, List<Student>> groupByCourse2 = students.stream().collect(Collectors.groupingBy(Student::getCourse, HashMap::new, Collectors.toList()));
System.out.println(groupByCourse2);
}
}
{数学=[Student(name=李四, age=17, clazz=高一2班, course=数学, score=90)], 语文=[Student(name=张三, age=16, clazz=高一1班, course=语文, score=88)], 外语=[Student(name=王五, age=18, clazz=高一3班, course=外语, score=100)]}
{数学=[Student(name=李四, age=17, clazz=高一2班, course=数学, score=90)], 语文=[Student(name=张三, age=16, clazz=高一1班, course=语文, score=88)], 外语=[Student(name=王五, age=18, clazz=高一3班, course=外语, score=100)]}
{数学=[Student(name=李四, age=17, clazz=高一2班, course=数学, score=90)], 语文=[Student(name=张三, age=16, clazz=高一1班, course=语文, score=88)], 外语=[Student(name=王五, age=18, clazz=高一3班, course=外语, score=100)]}
2.自定义键——字段映射![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/9b6cc419aa2e49ba8e30b0986b30562b.png)
package com.cy.demo;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class test {
public static void main(String[] args) {
List<Student> students = Stream.of(
new Student("张三", 16, "高一1班", "语文", 88),
new Student("李四", 17, "高一2班", "数学", 90),
new Student("王五", 18, "高一3班", "外语", 100)
).collect(Collectors.toList());
// 字段映射 分组显示每个课程的学生信息
Map<String, List<Student>> filedKey = students.stream().collect(Collectors.groupingBy(Student::getCourse));
System.out.println(filedKey);
// 组合字段 分组现实每个班不同课程的学生信息
Map<String, List<Student>> combineFiledKey = students.stream().collect(Collectors.groupingBy(student -> student.getClazz() + "#" + student.getCourse()));
System.out.println(combineFiledKey);
}
}
{数学=[Student(name=李四, age=17, clazz=高一2班, course=数学, score=90)],
语文=[Student(name=张三, age=16, clazz=高一1班, course=语文, score=88)],
外语=[Student(name=王五, age=18, clazz=高一3班, course=外语, score=100)]}
{高一2班#数学=[Student(name=李四, age=17, clazz=高一2班, course=数学, score=90)],
高一1班#语文=[Student(name=张三, age=16, clazz=高一1班, course=语文, score=88)],
高一3班#外语=[Student(name=王五, age=18, clazz=高一3班, course=外语, score=100)]}
3.自定义键——范围
package com.cy.demo;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class test {
public static void main(String[] args) {
List<Student> students = Stream.of(
new Student("张三", 16, "高一1班", "语文", 75),
new Student("李四", 17, "高一2班", "数学", 55),
new Student("王五", 18, "高一3班", "外语", 100)
).collect(Collectors.toList());
// 根据两级范围 将学生划分及格不及格两类
Map<Boolean, List<Student>> customRangeKey = students.stream().collect(Collectors.groupingBy(student -> student.getScore() > 60));
System.out.println(customRangeKey);
// 根据多级范围 根据学生成绩来评分
Map<String, List<Student>> customMultiRangeKey = students.stream().collect(Collectors.groupingBy(student -> {
if (student.getScore() < 60) {
return "C";
} else if (student.getScore() < 80) {
return "B";
}
return "A";
}));
System.out.println(customMultiRangeKey);
}
}
{false=[Student(name=李四, age=17, clazz=高一2班, course=数学, score=55)],
true=[Student(name=张三, age=16, clazz=高一1班, course=语文, score=75), Student(name=王五, age=18, clazz=高一3班, course=外语, score=100)]}
{A=[Student(name=王五, age=18, clazz=高一3班, course=外语, score=100)],
B=[Student(name=张三, age=16, clazz=高一1班, course=语文, score=75)],
C=[Student(name=李四, age=17, clazz=高一2班, course=数学, score=55)]}
4.计数 求和 平均值
package com.cy.demo;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class test {
public static void main(String[] args) {
List<Student> students = Stream.of(
new Student("张三", 16, "高一1班", "语文", 75),
new Student("李四", 17, "高一2班", "数学", 55),
new Student("王五", 18, "高一3班", "外语", 100),
new Student("赵六", 18, "高一1班", "语文", 88)
).collect(Collectors.toList());
// 计数
Map<String, Long> groupCount = students.stream()
.collect(Collectors.groupingBy(Student::getCourse, Collectors.counting()));
System.out.println(groupCount);
// 求和
Map<String, Integer> groupSum = students.stream()
.collect(Collectors.groupingBy(Student::getCourse, Collectors.summingInt(Student::getScore)));
System.out.println(groupSum);
// 增加平均值计算
Map<String, Double> groupAverage = students.stream()
.collect(Collectors.groupingBy(Student::getCourse, Collectors.averagingInt(Student::getScore)));
System.out.println(groupAverage);
}
}
3.Function.identity()
1.JDK源码
Java 8允许在接口中加入具体方法。接口中的具体方法有两种,default方法和static方法,identity()就是Function接口的一个静态方法。
- Function.identity()返回一个输出跟输入一样的Lambda表达式对象,等价于形如t -> t形式的Lambda表达式。
2.用法
当我们使用 Stream 想要将集合的某一属性(例如手机号)作为 key,对象本身作为 value 时,就可以在 Collectors.toMap() 中配合使用 Function.identity()。
// 查询数据
List<UserInfo> list = userInfoMapper.getList();
// 获取 手机号-UserInfo 映射
Map<String, UserInfo> phoneNumberMap = list.stream().collect(Collectors.toMap(UserInfo::getPhoneNumber(), Function.identity(), (v1, v2) -> v1));
不适用场景
不适用于 mapToInt()、mapToLong()、mapToDouble() 等需要进行拆箱操作的场景。
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3);
int[] array = list.stream().mapToInt(Function.identity()).toArray();
System.out.println(array.length);
}
3.案例
案例1
public static void main(String[] args) {
Stream<String> stream = Stream.of("This", "is", "a", "test");
Map<String, Integer> map = stream.collect(Collectors.toMap(Function.identity(), String::length));
System.out.println(map);
}
案例2
private static class Employee {
String id;
String age;
String name;
public Employee(String id, String age, String name) {
this.id = id;
this.name = name;
this.age = age;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Employee{" +
"id='" + id + '\'' +
", age='" + age + '\'' +
", name='" + name + '\'' +
'}';
}
}
public static void main(String[] args) {
List<Employee> list = Arrays.asList(new Employee("1","18","张三"),
new Employee("2","25","李四"),
new Employee("3","25","王五"));
Map<String, String> map1 = list.stream().collect(Collectors.toMap(Employee::getId, Employee::getName,(v1, v2) -> v2) );
System.out.println(map1.toString());
Map<String, Employee> map2 = list.stream().collect(Collectors.toMap(Employee::getId, Function.identity()));
System.out.println(map2.toString());
}
对比 Collectors.groupingBy
- Function.identity() 返回是对象本身 Map<String, Employee>
- Collectors.groupingBy 返回的是 Map<String, List< Employee>>
public static void main(String[] args) {
List<Employee> list = Arrays.asList(new Employee("1","18","张三"),
new Employee("2","25","李四"),
new Employee("3","25","王五"));
Map<String, String> map1 = list.stream().collect(Collectors.toMap(Employee::getId, Employee::getName,(v1, v2) -> v2) );
System.out.println(map1.toString());
Map<String, Employee> map2 = list.stream().collect(Collectors.toMap(Employee::getId, Function.identity()));
System.out.println(map2.toString());
Map<String, List<Employee>> map3 = list.stream().collect(Collectors.groupingBy(Employee::getId));
System.out.println(map3.toString());
Map<String, List<Employee>> map4 = list.stream().collect(Collectors.groupingBy(Employee::getAge));
System.out.println(map4.toString());
}