Collectors.toMap介绍
在真实的业务场景中有很多集合转map的操作,例如
@Data
public class House {private Integer id; //idprivate Integer ownerid; //家主编号private String housename; //家庭名称private String address; //家庭地址}
模拟数据
/*** @description: List 转 Map 操作*/
public class ListToMap {public static void main(String[] args) {House house = new House(1,1,"aa","北京海淀");House house1 = new House(2,2,"bb","湖北武汉");House house2 = new House(3,3,"cc","浙江杭州");ArrayList<House> houses = new ArrayList<>();houses.add(house);houses.add(house1);houses.add(house2);//在实际项目中我们经常会用到 List 转 Map 操作 ->过去是for循环的操作,现在可以学习如下的方法Collectors.toMap/*** 我们收集一下集合中每个对象的两个单独的属性*/Map<String, String> mapHouse = houses.stream().collect(Collectors.toMap(House::getHousename, House::getAddress));System.out.println(mapHouse);//{aa=湖北武汉, bb=浙江杭州, cc=北京海淀}/*** 前后的属性的数据类型要对应 一般时间业务中收集带有唯一表示的业务数据*/Map<Integer, String> map = houses.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename));System.out.println(map);//{1=aa, 2=bb, 3=cc}/*** 收集一下属性和对象本身*/Map<Integer, House> houseMap = houses.stream().collect(Collectors.toMap(House::getOwnerid, o -> o));Map<Integer, House> houseMap1 = houses.stream().collect(Collectors.toMap(House::getOwnerid, Function.identity()));System.out.println(houseMap);/*** {1=House{id=1, ownerid=1, housename='aa', address='北京海淀'}, * 2=House{id=2, ownerid=2, housename='bb', address='湖北武汉'}, * 3=House{id=3, ownerid=3, housename='cc', address='浙江杭州'}}*///业务场景:一般会根据具体的键值 取具体的对象System.out.println(houseMap.get(1));//House{id=1, ownerid=1, housename='aa', address='北京海淀'}//此处的效果同houseMapSystem.out.println(houseMap1);/*** {1=House{id=1, ownerid=1, housename='aa', address='北京海淀'}, * 2=House{id=2, ownerid=2, housename='bb', address='湖北武汉'}, * 3=House{id=3, ownerid=3, housename='cc', address='浙江杭州'}}*/}}
常见操作大家实践即可
houses.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename));
深入Collectors.toMap
Collectors.toMap 有三个重载方法:
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper);
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,BinaryOperator<U> mergeFunction);
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier);
参数含义分别是:
keyMapper:Key 的映射函数
valueMapper:Value 的映射函数
mergeFunction:当 Key 冲突时,调用的合并方法
mapSupplier:Map 构造器,在需要返回特定的 Map 时使用
业务场景最多的还是map的键为一个唯一的标识符,值为对象本身!
如果希望得到 Map 的 value 为对象本身时,可以这样写
/*** 收集一下属性和对象本身*/
Map<Integer, House> houseMap = houses.stream().collect(Collectors.toMap(House::getOwnerid, o -> o));
Map<Integer, House> houseMap1 = houses.stream().collect(Collectors.toMap(House::getOwnerid, Function.identity()));
常见的java.lang.IllegalStateException: Duplicate key 问题处理
我们把做的测试数据 House house = new House(1,1,“aa”,“北京海淀”);
House house1 = new House(2,2,“bb”,“湖北武汉”);
House house2 = new House(3,3,“cc”,“浙江杭州”);
house2修改为: House house2 = new House(3,1,“cc”,“浙江杭州”);
这样Ownerid会重复
当我们执行如下代码时:houses.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename);
会出错,java.lang.IllegalStateException: Duplicate key
线上业务代码出现Duplicate Key的异常,影响了业务逻辑,查看抛出异常部分的代码
Exception in thread "main" java.lang.IllegalStateException: Duplicate key aaat java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)at java.util.HashMap.merge(HashMap.java:1254)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:1382)at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)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 com.example.cwgl.ListToMap.main(ListToMap.java:28)
解决办法:出现重复时,取前面value的值,或者取后面放入的value值,则覆盖先前的value值
houses.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename,(v1,v2)->v2));
houses.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename,(v1,v2)->v1));
对于结果的操作还有很多处理方法,如拼接等
houses.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename,(v1,v2)->v1+v2));
具体的实践根据具体的业务来操作数据即可
List统计重复数量
final String path = "F:/AppData/API-url.txt";
final List<String> list = BlockIOUtil.readLines("file:" + path);
Map<String, Integer> map = list.stream().collect(Collectors.toMap(it -> it, it -> 1, (val1, val2) -> val1 + 1));
for (Map.Entry<String, Integer> entry : map.entrySet()) {if (entry.getValue() != null && entry.getValue() > 1) {System.out.println(entry.getKey() + "-->" + entry.getValue());}
}