使用Collectors.toMap()转换String列表为Map时触发IllegalStateException的原因
问题分析与解决方案:Collectors.toMap() 触发 IllegalStateException 重复Key问题
你遇到的这个异常,核心原因其实很明确——你用listOfCities::indexOf生成Map的Key,但这个方法会给重复元素返回相同的索引,直接违反了Map的Key唯一性要求。
为什么会出现重复Key?
List.indexOf()方法的逻辑是:返回列表中第一个匹配目标元素的索引。举个例子,你的列表里有两个"Istanbul":
- 第一个"Istanbul"的索引是0,处理它时Key是0;
- 处理第二个"Istanbul"时,调用
indexOf("Istanbul")还是会返回0,这就导致两个元素的Key都是0,Collectors.toMap()遇到重复Key时,默认会抛出IllegalStateException。
解决方案:用当前元素的真实索引作为Key
如果你想要每个元素对应唯一的Key(也就是它们在列表中的真实位置),可以用IntStream.range来遍历索引,而不是直接遍历列表元素:
public class CollectorsDemo5 { public static void main(String[] args) { List<String> listOfCities=new ArrayList<String>(); listOfCities.add("Istanbul"); listOfCities.add("Istanbul"); listOfCities.add("Budapest"); listOfCities.add("Delhi"); listOfCities.add("Amsterdam"); listOfCities.add("Canberra"); listOfCities.add("Canberra"); // 使用IntStream获取每个元素的真实索引 Map<Integer, String> map = IntStream.range(0, listOfCities.size()) .boxed() .collect(Collectors.toMap( Function.identity(), // 索引作为Key index -> listOfCities.get(index) // 索引对应的元素作为Value )); map.forEach((k,v)->System.out.println("key:"+k +" value:"+v)); } }
运行这段代码,输出会是每个元素对应自己的真实位置索引,完全不会有重复Key的问题:
key:0 value:Istanbul key:1 value:Istanbul key:2 value:Budapest key:3 value:Delhi key:4 value:Amsterdam key:5 value:Canberra key:6 value:Canberra
备选方案:处理重复Key(如果需要保留重复Key的逻辑)
如果你确实需要用indexOf()生成Key,但想避免异常,可以在toMap()中添加合并函数,指定遇到重复Key时如何处理,比如保留第一个出现的元素:
Map<Integer, String> map = listOfCities.stream() .collect(Collectors.toMap( listOfCities::indexOf, Function.identity(), (existingVal, newVal) -> existingVal // 重复时保留旧值 ));
不过这种方式会丢弃后续的重复元素(比如第二个"Istanbul"会被忽略),所以只有当你不需要保留所有元素时才适用。
内容的提问来源于stack exchange,提问作者saroj
相关产品推荐
相关产品推荐

