Java Map的computeIfAbsent方法去重详解

小豆丁 21小时前 ⋅ 5 阅读
聊天记录
头像

java Map的使用computeIfAbsent去重

头像

Java 中 Map.computeIfAbsent() 方法可以用于去重场景,特别是当需要根据键生成复杂值或维护键对应的集合时。以下是几种常见用法:

1. 基础去重示例

JAVA
Map<String, String> map = new HashMap<>();
List<String> names = Arrays.asList("Alice", "Bob", "Alice", "Charlie", "Bob");

// 去重并标记首次出现
for (String name : names) {
    map.computeIfAbsent(name, k -> "First seen: " + k);
}

// 结果: {Alice=First seen: Alice, Bob=First seen: Bob, Charlie=First seen: Charlie}
System.out.println(map);

2. 分组去重(一对多映射)

JAVA
Map<String, List<String>> groupMap = new HashMap<>();
String[][] data = {
    {"Group1", "A"}, {"Group1", "B"},
    {"Group2", "C"}, {"Group1", "A"}  // 重复的 A
};

for (String[] pair : data) {
    groupMap.computeIfAbsent(pair[0], k -> new ArrayList<>());
    if (!groupMap.get(pair[0]).contains(pair[1])) {
        groupMap.get(pair[0]).add(pair[1]);
    }
}
// 结果: Group1=[A, B], Group2=[C]

3. 计数去重

JAVA
Map<String, Integer> countMap = new HashMap<>();
String[] words = {"apple", "banana", "apple", "orange", "banana", "banana"};

for (String word : words) {
    countMap.computeIfAbsent(word, k -> 0);
    countMap.put(word, countMap.get(word) + 1);
}
// 结果: {apple=2, banana=3, orange=1}

4. 对象属性去重

JAVA
class Person {
    String id;
    String name;
    // 构造器、getter/setter
}

List<Person> persons = Arrays.asList(
    new Person("1", "Alice"),
    new Person("2", "Bob"),
    new Person("1", "Alice")  // 重复ID
);

Map<String, Person> personMap = new HashMap<>();
for (Person p : persons) {
    personMap.computeIfAbsent(p.getId(), k -> p);
}
// 结果: 只有两个不重复的Person

5. 使用 ConcurrentHashMap 线程安全去重

JAVA
ConcurrentMap<String, String> concurrentMap = new ConcurrentHashMap<>();
List<String> items = Arrays.asList("A", "B", "A", "C", "B");

items.parallelStream().forEach(item -> {
    concurrentMap.computeIfAbsent(item, k -> "Processed: " + k);
});

6. 复杂值初始化示例

JAVA
Map<String, Set<Integer>> complexMap = new HashMap<>();
String[][] records = {
    {"user1", "100"}, {"user1", "200"},
    {"user2", "300"}, {"user1", "100"}  // 重复
};

for (String[] record : records) {
    complexMap.computeIfAbsent(record[0], k -> new HashSet<>())
              .add(Integer.parseInt(record[1]));
}
// 结果: user1=[100, 200], user2=[300]

7. 与 Stream API 结合

JAVA
List<String> duplicates = Arrays.asList("a", "b", "a", "c", "b", "a");

// 获取首次出现的位置
Map<String, Integer> firstOccurrence = new HashMap<>();
for (int i = 0; i < duplicates.size(); i++) {
    int index = i;
    firstOccurrence.computeIfAbsent(duplicates.get(i), k -> index);
}
// 结果: {a=0, b=1, c=3}

关键点总结

  1. computeIfAbsent 方法签名

    JAVA
    V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
    
    • 如果键不存在,使用函数计算值并存入
    • 如果键存在,直接返回现有值
  2. 去重优势

    • 避免不必要的对象创建
    • 代码更简洁,避免 if (!map.containsKey(key)) 检查
    • 原子性操作(在 ConcurrentHashMap 中)
  3. 注意事项

    • 映射函数不应有副作用
    • 在非并发映射中,非线程安全
    • 映射函数返回 null 时会抛出异常

这种方法特别适合需要初始化复杂值(如集合、对象)的去重场景。

全部评论: 0

    我有话说: