Java 8中Collection转为Map的方法
Java 8中java.util.stream.Collectors提供了几个方法可用于把Collection转为Map结构,本文记录了个人对其中三个的理解。
| Method | Return Type |
|---|---|
| groupingBy | Map<K, List<T>> |
| partitioningBy | Map<Boolean, List<T>> |
| toMap | Map<K,U> |
1. 环境
Java: jdk1.8.0_144
2. 特性说明
Student.java
public class Student {
private String studentNo;
private String name;
private Boolean gender;
private int age;
public Student(String studentNo, String name, Boolean gender, int age) {
this.studentNo = studentNo;
this.name = name;
this.gender = gender;
this.age = age;
}
public String getStudentNo() {
return studentNo;
}
public String getName() {
return name;
}
public Boolean getGender() {
return gender;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return String.format("Student [studentNo=%s, name=%s, gender=%s, age=%s]", studentNo, name, gender, age);
}
}
fakeStudent()方法
private List<Student> fakeStudent() {
List<Student> students = new ArrayList<>();
students.add(new Student("1", "name1", false, 2));
students.add(new Student("2", "name2", false, 2));
students.add(new Student("3", "name2", null, 2));
students.add(new Student("4", "name4", true, 2));
students.add(new Student(null, "name5", true, 2));
return students;
}
2.1. Collectors.groupingBy
public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier) {
return groupingBy(classifier, toList());
}
a) 按Function的返回值把集合分组,并以之为Key,对应的列表为Value,返回Map
b) 若Key对应的列表为空时,返回的Map中将不包含该Key
c) 若Function的返回值为Null,抛出NullPointerException
@Test(expected = NullPointerException.class)
public void shouldThrowNPEWhenGroupingByNullKey() {
fakeStudent().stream().collect(Collectors.groupingBy(Student::getStudentNo));
}
2.2. Collectors.partitioningBy
public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {
return partitioningBy(predicate, toList());
}
a) 按Predicate的返回值把集合分为两组,符合条件的列表以true为Key,不符合的列表以false为Key
b) 若Predicate的返回值为Null,抛出NullPointerException
@Test(expected = NullPointerException.class)
public void shouldReturnMapWhenPartitioningByNullKey() {
fakeStudent().stream().collect(Collectors.partitioningBy(Student::getGender));
}
2.3. Collectors.toMap
public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper) {
return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
}
a) 以keyMapper的Function返回值为Key且以valueMapper的Function返回值为Value,形成Map
b) 若Key为Null,依然可以正确返回
@Test
public void shouldReturnMapWhenToMapNullKey() {
Map<String, Student> map = fakeStudent().stream()
.collect(Collectors.toMap(Student::getStudentNo, Function.identity()));
assertEquals("{null=Student [studentNo=null, name=name5, gender=true, age=2], "
+ "1=Student [studentNo=1, name=name1, gender=false, age=2], "
+ "2=Student [studentNo=2, name=name2, gender=false, age=2], "
+ "3=Student [studentNo=3, name=name2, gender=null, age=2], "
+ "4=Student [studentNo=4, name=name4, gender=true, age=2]}", map.toString());
}
c) 若Key值出现重复,默认抛出IllegalStateException
@Test
public void shouldThrowIllegalStateExceptionWhenToMapDuplicateKey() {
Map<String, Student> map = null;
try {
map = fakeStudent().stream().collect(Collectors.toMap(Student::getName, Function.identity()));
} catch (Exception e) {
assertTrue(e instanceof IllegalStateException);
assertEquals("Duplicate key Student [studentNo=2, name=name2, gender=false, age=2]", e.getMessage());
}
assertNull(map);
}
若需要避免Duplicate Key的问题,可以有两个选择
- 确定toMap的冲突策略,例如指定前者
@Test
public void shouldReturnMapWhenToMapDuplicateKey() {
Map<String, Student> map = fakeStudent().stream()
.collect(Collectors.toMap(Student::getName, Function.identity(), (student1, student2) -> student1));
assertEquals("{name5=Student [studentNo=null, name=name5, gender=true, age=2], "
+ "name4=Student [studentNo=4, name=name4, gender=true, age=2], "
+ "name2=Student [studentNo=2, name=name2, gender=false, age=2], "
+ "name1=Student [studentNo=1, name=name1, gender=false, age=2]}", map.toString());
}
- 放弃toMap方法,而利用collect
@Test
public void shouldReturnMapWhenCollectDuplicateKey() {
Map<String, Student> map = fakeStudent().stream().collect(HashMap::new, (m, v) -> m.put(v.getName(), v),
HashMap::putAll);
assertEquals("{name5=Student [studentNo=null, name=name5, gender=true, age=2], "
+ "name4=Student [studentNo=4, name=name4, gender=true, age=2], "
+ "name2=Student [studentNo=3, name=name2, gender=null, age=2], "
+ "name1=Student [studentNo=1, name=name1, gender=false, age=2]}", map.toString());
}
d) 若Value为Null,则抛出NullPointerException
@Test(expected = NullPointerException.class)
public void shouldThrowNPEWhenToMapNullValue() {
fakeStudent().stream().collect(Collectors.toMap(Student::getStudentNo, Student::getGender));
}
3. 结语
- Collectors.groupingBy/Collectors.partitioningBy中心思想都是把原来集合以某种条件分组,分组条件不能为Null;只是Collectors.partitioningBy的分组条件是断言,且永远返回true/false对应的两组值,它们对应的Value可能是空列表,而Collectors.groupingBy的分组结果是空列表则会被抛弃
@Test
public void shouldReturnSameMapWhenGroupingByAndPartitioningBy() {
List<Student> students = fakeStudent().stream().filter(student -> student.getGender() != null)
.collect(Collectors.toList());
Map<Boolean, List<Student>> groupingByMap = students.stream()
.collect(Collectors.groupingBy(Student::getGender));
Map<Boolean, List<Student>> partitioningByMap = students.stream()
.collect(Collectors.partitioningBy(Student::getGender));
assertEquals("{false=[Student [studentNo=1, name=name1, gender=false, age=2], "
+ "Student [studentNo=2, name=name2, gender=false, age=2]], "
+ "true=[Student [studentNo=4, name=name4, gender=true, age=2], "
+ "Student [studentNo=null, name=name5, gender=true, age=2]]}", groupingByMap.toString());
assertEquals(groupingByMap.toString(), partitioningByMap.toString());
}
@Test
public void shouldReturnDifferentMapWhenGroupingByAndPartitioningBy() {
Function<Student, Boolean> function = student -> student.getAge() > 3;
List<Student> students = fakeStudent();
Map<Boolean, List<Student>> groupingByMap = students.stream().collect(Collectors.groupingBy(function));
Map<Boolean, List<Student>> partitioningByMap = students.stream()
.collect(Collectors.partitioningBy(function::apply));
assertEquals("{false=[Student [studentNo=1, name=name1, gender=false, age=2], "
+ "Student [studentNo=2, name=name2, gender=false, age=2], "
+ "Student [studentNo=3, name=name2, gender=null, age=2], "
+ "Student [studentNo=4, name=name4, gender=true, age=2], "
+ "Student [studentNo=null, name=name5, gender=true, age=2]]}", groupingByMap.toString());
assertEquals(
"{false=[Student [studentNo=1, name=name1, gender=false, age=2], "
+ "Student [studentNo=2, name=name2, gender=false, age=2], "
+ "Student [studentNo=3, name=name2, gender=null, age=2], "
+ "Student [studentNo=4, name=name4, gender=true, age=2], "
+ "Student [studentNo=null, name=name5, gender=true, age=2]], true=[]}",
partitioningByMap.toString());
}
- Collectors.toMap与Collectors.groupingBy/Collectors.partitioningBy不一样,它只负责把集合中的元素根据某种形式拆解为一个Map,该Map的key可以为Null但不允许重复,同时Map的Value不可以为Null
4. 参考资料
- 附代码地址
https://github.com/hivsuper/study/blob/master/study-java8/src/test/java/org/lxp/java8/map/CollectionToMapTest.java - https://stackoverflow.com/questions/27993604/whats-the-purpose-of-partitioningby
Java 8中Collection转为Map的方法的更多相关文章
- 【转】java 容器类使用 Collection,Map,HashMap,hashTable,TreeMap,List,Vector,ArrayList的区别
原文网址:http://www.360doc.com/content/15/0427/22/1709014_466468021.shtml java 容器类使用 Collection,Map,Hash ...
- SuperDiamond在JAVA项目中的三种应用方法实践总结
SuperDiamond在JAVA项目中的三种应用方法实践总结 1.直接读取如下: @Test public static void test_simple(){ PropertiesConfigur ...
- Java编程中获取键盘输入实现方法及注意事项
Java编程中获取键盘输入实现方法及注意事项 1. 键盘输入一个数组 package com.wen201807.sort; import java.util.Scanner; public clas ...
- java中collection、map、set、list简介 (转)
Collection接口 Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements).一些Collection允许相同的元 ...
- 【Java心得总结六】Java容器中——Collection
在[Java心得总结五]Java容器上——容器初探这篇博文中,我对Java容器类库从一个整体的偏向于宏观的角度初步认识了Java容器类库.而在这篇博文中,我想着重对容器类库中的Collection容器 ...
- Java开发中碰到的Map的坑
这属于我在开发中碰过的坑 ,容器中存放者对象,当clear()的时候,出现的奇葩问题.好了,直接看代码: package com.DataType.yinyong; import java.util. ...
- java Iterator Iterable Collection AbstractCollection Map关系
java.lang Interface Iterable<T> 实现该接口就可以使用for-each循环. java.util Interface Iterator<E> ...
- Java 8 中为什么要引出default方法
(原) default方法是java 8中新引入进的,它充许接口中除了有抽象方法以外,还可以拥用具有实现体的方法,这一点跟jdk8之前的版本已经完全不一样了,为什么要这样做呢? 拿List接口举例,在 ...
- java 接口中的成员变量与方法
java接口中变量的默认修饰符为 public static final int i = 3; 相当于 public static final int i = 3; java接口中方法的默认修饰符为 ...
随机推荐
- Go -- 并发编程的两种限速方法
引子 golang提供了goroutine快速实现并发编程,在实际环境中,如果goroutine中的代码要消耗大量资源时(CPU.内存.带宽等),我们就需要对程序限速,以防止goroutine将资源耗 ...
- 【Todo】一些scala的实验 & 与Java的混合
另外,如果要支持 java 和 scala混合build,可以看看这篇文章: http://www.cnblogs.com/yjmyzz/p/4694219.html Scala和Java实现Word ...
- 【CV知识学习】神经网络梯度与归一化问题总结+highway network、ResNet的思考
这是一篇水货写的笔记,希望路过的大牛可以指出其中的错误,带蒟蒻飞啊~ 一. 梯度消失/梯度爆炸的问题 首先来说说梯度消失问题产生的原因吧,虽然是已经被各大牛说烂的东西.不如先看一个简单的网络结构 ...
- c++单元测试指南:使用google test
Reference:http://www.codeproject.com/Articles/811934/Cplusplus-unit-test-start-guide-how-to-set-up-G ...
- centos 7 安装官方LAMP(Apache+PHP5+MySQL)
启用Apache2 yum install httpd systemctl start httpd.service systemctl status httpd systemctl enable ht ...
- ProFTPD配置匿名登录与文件夹訪问权限控制
对ProFTPDserver配置匿名登录. 查看配置文件proftpd.conf.默认情况下配置文件里的.匿名登录配置User和Group均为ftp. 查看/etc/passwd确认用 ...
- ios9定位服务的app进入后台三分钟收不到经纬度,应用被挂起问题及解决方式
原来定位服务是10分钟收不到定位信息就挂起定位,如今变为最短3分钟,预计都是为了省电吧. 仅仅要你开启应用的后台定位,而且10分钟有一次定位,那么苹果就不会关闭你的线程.如今变成3分钟.若你的应用开启 ...
- weex splash页面
1.Splash.vue <!-- splash页面 --> <template> <div class="wrap" @focus="ro ...
- Effective C++ 条款三 尽可能使用const
参考资料:http://blog.csdn.net/bizhu12/article/details/6672723 const的常用用法小结 1.用于定义常量变量,这样这个变量在后面就不可以 ...
- MySql视频教程——百度云下载路径
百度云分享MySql视频教程给大家.祝大家事业进步! MySql视频教程:http://pan.baidu.com/s/1gdCHX79 password:n46i