java8对象数组转集合的简单操作
java8版本对传统的集合类的简单操作结合拉姆达表达式相比之前版本方便快捷,很大程度减少了代码量。相对数据库而言大大的减少了数据处理数据的压力。部分统计可以转移在程序中处理。stream 流进行强大的统计转换功能。
下面我们先看下例子:先建立一个student类:
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
@Override
public String toString() {
//这里JSON.toJSONString 用的是fastJson
return "Student" + JSON.toJSONString(this);
}
public Student(){
}
public Student(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
}
这里的 @Data 注解是使用了Lombok插件。 不懂的大家可以自行看Lombok官网使用说明。
idea配置Lombok 也非常简单
- 下载插件 setting -> plugins->搜索lombok
- 设置允许插件处理。Build,Execution,deployment ->compiler->Annotation processors 中在enable anntation processing 打上对号。
- 在你的项目maven 中添加 Lombok 依赖
- 重启你的idea 这样就完成Lombok 安装。
先初始化一个List
List<Student> stuList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Student stu = new Student();
stu.setId(i);
stu.setName("李雷" + i);
stu.setAge(new Random().nextInt(10));
stuList.add(stu);
}
我们生成的数据 id 为从0-9一共10 个,age 以为是0-10 的随机数,可能会有重复。名字是李雷0-李雷9。下面我们来进行数据测试:
- 我们把id 转换为list java8之前的方法我就不再演示了相信大家都会。
List<Integer> ids = stuList.stream().map(Student::getId).collect(Collectors.toList());
结果:为转换后的id是:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
一行代码搞定相当方便。那么 我们把年龄转为Set 怎么处理呢?
同理:
Set<Integer> ages = stuList.stream().map(Student::getAge).collect(Collectors.toSet());
System.out.println("转换后的不重复age是:" + ages);
结果:转换后的不重复age是:[1, 2, 5, 7]
相当方便。
- 下面假如我们有个需求,需要把Studen对象放到map中取,id为map的key
//转换成map
Map<Integer, Student> collect = stuList.stream().collect(Collectors.toMap(Student::getId, vo -> vo));
System.out.println("转换后Map值是实体:" + collect);
结果:转换后Map值是实体:
{0=Student{"age":1,"id":0,"name":"李雷0"},
1=Student{"age":5,"id":1,"name":"李雷1"},
2=Student{"age":1,"id":2,"name":"李雷2"},
3=Student{"age":7,"id":3,"name":"李雷3"},
4=Student{"age":7,"id":4,"name":"李雷4"},
5=Student{"age":7,"id":5,"name":"李雷5"},
6=Student{"age":7,"id":6,"name":"李雷6"},
7=Student{"age":5,"id":7,"name":"李雷7"},
8=Student{"age":1,"id":8,"name":"李雷8"},
9=Student{"age":2,"id":9,"name":"李雷9"}}
如果我们不需要把实体放在map中去。
Map<Integer, String> mapNameIds = stuList.stream().collect(Collectors.toMap(Student::getId, Student::getName));
System.out.println("转换后Map值是:" + mapNameIds);
结果:转换后Map值是姓名:{0=李雷0, 1=李雷1, 2=李雷2, 3=李雷3, 4=李雷4,
5=李雷5, 6=李雷6, 7=李雷7, 8=李雷8, 9=李雷9}
如果我们需要把年纪作为key,id做为值存入map
Map<Integer, Integer> mapNameIds = stuList.stream().collect(Collectors.toMap(Student::getAge, Student::getId));
System.out.println("转换后Map值是姓名:" + mapNameIds);
一看执行结果???? 怎么报错了
我们看下 toMap 源码 注释上面写了
* <p>If the mapped keys contains duplicates (according to
* {@link Object#equals(Object)}), an {@code IllegalStateException} is
* thrown when the collection operation is performed. If the mapped keys
* may have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
* 上面说如果 map中的key 相同 会抛出 异常,我们可以使用重载方法
* toMap(Function, Function, BinaryOperator) 去处理
* instead.
修改代码如下:
//如果key值相同 对应的value 取大的那个 两种写法都可以
Map<Integer, Integer> mapNameIdsGt = stuList.stream().collect(Collectors.toMap(Student::getAge, Student::getId
, (id1, id2) -> (id1 > id2 ? id1 : id2)));
Map<Integer, Integer> mapNameIdsGt =
stuList.stream().collect(Collectors.toMap(Student::getAge, Student::getId
, Math::max));
System.out.println("转换后Map值是:" + mapNameIdsGt);
结果为:转换后Map值是:{0=8, 1=0, 3=9, 5=3, 6=4, 7=5, 9=7}
//如果key值相同 对应的value 值相加
Map<Integer, Integer> mapNameIdsAdd = stuList.stream().collect(Collectors.toMap(Student::getAge, Student::getId
, Integer::sum));
System.out.println("转换后Map值是:" + mapNameIdsAdd);
结果为:转换后Map值是:{0=16, 1=0, 3=10, 5=3, 6=4, 7=5, 9=7}
如果我们想把对象中name 和age 放入数组中 作为map 的值又该怎办呢?
Map<Integer, List<String>> mapListNameAndAge = stuList.stream().collect(Collectors.toMap(Student::getId, s -> {
List<String> list = new ArrayList<>();
list.add(s.getName());
list.add(s.getAge().toString());
return list;
}
));
System.out.println("转换后Map值是:" + mapListNameAndAge);
结果为:
转换后Map值是:{0=[李雷0, 1], 1=[李雷1, 3], 2=[李雷2, 0],
3=[李雷3, 5], 4=[李雷4, 6], 5=[李雷5, 7], 6=[李雷6, 0], 7=[李雷7, 9],
8=[李雷8, 0], 9=[李雷9, 3]}
- 我们想把list中数据按照年纪正序 或者倒序
//排序按照年纪倒序
stuList.sort(Comparator.comparing(Student::getAge).reversed());
System.out.println(stuList);
//按照年纪正序
stuList.sort(Comparator.comparing(Student::getAge));
System.out.println(stuList);
//按照年纪倒序,年纪相同按照 id 倒序
stuList.sort(Comparator.comparing(Student::getAge).thenComparing(Student::getId).reversed());
System.out.println(stuList);
下面介绍常用一些方法:
//计算总年纪和
Integer ageSum = stuList.stream().map(Student::getAge).reduce(0, Integer::sum);
System.out.println(ageSum);
//计算总id积
Integer productId = stuList.stream().map(Student::getId).reduce(1, (i, j) -> i * j);
System.out.println(productId);
//按照年纪分组
Map<Integer, List<Student>> groupByAgeMap = stuList.stream().collect(Collectors.groupingBy(Student::getAge));
System.out.println(groupByAgeMap);
//查找年纪最大的 如果有相同的取 年纪升序
Student studentAgeMax = stuList.stream().max(Comparator.comparing(Student::getAge)).orElse(null);
System.out.println("age" + studentAgeMax);
//查询姓名为李雷1的的同学。不存在返回一个new studen() 实体
Student student = stuList.stream().filter(s -> s.getName().equals("李雷1")).findAny().orElseGet(Student::new);
System.out.println(student);
/**
* 如果我们想得到 李雷1这个人的年纪 我们可以有两种写法
*/
//方法1:我们可以把 Student::new 换成一个初始化的方法,让student为空时候初始化age数据
Integer age = stuList.stream().filter(s -> s.getName().equals("李雷1"))
.findAny().orElseGet(Student::new).getAge();
//方法2:
Integer age = stuList.stream().filter(s -> s.getName().equals("韩梅梅")).findAny()
.map(Student::getAge).orElseGet(() -> 18);
System.out.println(age);
说明:这里的orElse 和orElseGet 是 java8 Optional 类中的方法。具体使用我们下次介绍。