You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何向HashMap内的ArrayList添加元素实现字符索引映射

问题说明

需求为遍历存储字符的ArrayList,构建HashMap:键为列表中的字符,值为该字符在列表中所有出现位置的索引组成的ArrayList。
示例输入数组:[X,X,Y,Z,X],预期返回映射结构:

{
  X: [0,1,4],
  Y: [2],
  Z: [3]
}

原有代码运行报错的核心原因:ArrayList.add()方法返回值为boolean类型,但computeIfPresent方法传入的lambda表达式要求返回更新后的值对象(即List类型),类型不匹配。另外原有代码中声明的arrayOfIndexes变量未被任何逻辑使用,可直接删除。原有错误代码如下:

/* turn the pattern into a List of characters
        turn the List into a HashMap with the keys as the characters and 
        the values as the indexes of the characters in the List
        */
        ArrayList<Character> listOfPatternChars = convertStringToCharList(userPattern);
        HashMap<Character,ArrayList<Integer>> mapOfPatternCharsIndex = new HashMap<Character,ArrayList<Integer>>();
        
        ArrayList<ArrayList<Integer>> arrayOfIndexes = new ArrayList<ArrayList<Integer>>();

        for (int i = 0; i < listOfPatternChars.size(); i++) {
            mapOfPatternCharsIndex.putIfAbsent(listOfPatternChars.get(i), new ArrayList<Integer>());
            mapOfPatternCharsIndex.computeIfPresent(listOfPatternChars.get(i), (k,v) -> v.add(i) );
        }

疑问点:JavaScript中可通过展开运算符实现(k, v) => [...v,i]的更新逻辑,Java中是否存在类似实现。

解决方案

Java没有和JavaScript展开运算符完全等价的语法糖,针对该场景可按以下方式实现:

  • 修复原有computeIfPresent写法:ArrayList是可变对象,add操作会直接修改原列表内容,只需要在lambda中执行add后返回原列表对象即可,修正后循环逻辑:
for (int i = 0; i < listOfPatternChars.size(); i++) {
    Character currentChar = listOfPatternChars.get(i);
    mapOfPatternCharsIndex.putIfAbsent(currentChar, new ArrayList<>());
    mapOfPatternCharsIndex.computeIfPresent(currentChar, (k, v) -> {
        v.add(i);
        return v;
    });
}

代码中使用Java 7+支持的菱形语法简化泛型声明,同时用临时变量存储当前遍历的字符,避免重复调用get(i)取值,减少冗余计算。

  • 更简洁的标准写法:直接用computeIfAbsent合并初始化和取值逻辑,无需分开写putIfAbsent和computeIfPresent,代码更短且逻辑更清晰:
for (int i = 0; i < listOfPatternChars.size(); i++) {
    mapOfPatternCharsIndex.computeIfAbsent(listOfPatternChars.get(i), key -> new ArrayList<>())
            .add(i);
}

该写法逻辑为:computeIfAbsent会先判断键是否存在,若不存在则通过lambda生成新的ArrayList作为对应值存入Map,最终返回该键关联的值(无论值是原有还是新生成的),拿到值后直接调用add(i)存入当前索引即可,完全规避返回值类型不匹配的问题,是这类分组收集索引场景的通用实现。

如果要实现类似JS展开运算符那种「不修改原列表,基于原列表生成追加元素后的新列表」的不可变逻辑,Java 8+可通过Stream API实现:

(k, v) -> Stream.concat(v.stream(), Stream.of(i)).collect(Collectors.toList())

但该方式每次追加元素都会生成全新的列表,性能远低于直接修改可变列表的方案,仅在需要保证原列表不可变的特殊场景下使用,当前场景不推荐。

内容的提问来源于stack exchange,提问作者João Pedro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 02:33:08