背景
在开发过程中,我们经常要将list按照规则转为map,而jdk8提供了一个很好的工具:Collections.toMap,使用这个方法时,往往会有一些坑。
Collections.toMap示例
创建一个pojo
import java.io.Serializable; import lombok.Data; @Data public class Student implements Serializable{ private static final long serialVersionUID = 1L; //字段 private Integer id; private String firstName; private String lastName; private Integer age; public static Student createStudent(Integer id,String firstName,String lastName,Integer age) { Student st=new Student(); st.id=id; st.firstName=firstName; st.lastName=lastName; st.age=age; return st; } @Override public String toString() { return "student [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", age=" +age+ ']'; } }
创建测试类
import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class MapTest { public static void main(String[] args) { List<Student> sts=new ArrayList<Student>(); sts.add(Student.createStudent(1, "david", "wang", 20)); sts.add(Student.createStudent(2, "david1", "wang1", 21)); sts.add(Student.createStudent(2, "david2", "wang2", 22)); Map<Integer,Student> id_student=sts.stream().collect(Collectors.toMap(Student::getId, student ->student)); System.out.println("Collections.toMap test:"+id_student.get(2).getFirstName()); } }
报错信息:
Exception in thread "main" java.lang.IllegalStateException: Duplicate key student [id=2, firstName=david1, lastName=wang1, age=21] at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133) at java.util.HashMap.merge(HashMap.java:1245) at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320) at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169) at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) at MapTest.main(MapTest.java:13)
解决方法
保留1:
import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class MapTest { public static void main(String[] args) { List<Student> sts=new ArrayList<Student>(); sts.add(Student.createStudent(1, "david", "wang", 20)); sts.add(Student.createStudent(2, "david1", "wang1", 21)); sts.add(Student.createStudent(2, "david2", "wang2", 22)); Map<Integer,Student> id_student=sts.stream().collect(Collectors.toMap(Student::getId, student -> student,(v1,v2) -> v1)); System.out.println("Collections.toMap test:"+id_student.get(2).getFirstName()); } }
结果
Collections.toMap test:david1
保留2:
import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class MapTest { public static void main(String[] args) { List<Student> sts=new ArrayList<Student>(); sts.add(Student.createStudent(1, "david", "wang", 20)); sts.add(Student.createStudent(2, "david1", "wang1", 21)); sts.add(Student.createStudent(2, "david2", "wang2", 22)); Map<Integer,Student> id_student=sts.stream().collect(Collectors.toMap(Student::getId, student -> student,(v1,v2) -> v2)); System.out.println("Collections.toMap test:"+id_student.get(2).getFirstName()); } }
结果
Collections.toMap test:david2
结论
public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction) { return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new); }
参数:
第一个参数为要组成的Map的Key,例如上面例子中用ManualEntry的Id做key;
第二个参数为map的value,例如例子中要生成的value为manualEntry.getGroupInsIds()分割后组成的List的合集
第三个参数则为key重复时处理方法:例子中的处理方式是如果重复,使用value2,即覆盖,也可以做其他处理