Map之computeIfAbsent

computeIfAbsent方法是Java8中Map接口的新特性,用于在获取值时自动检查并生成缺失的值,减少样板代码,提高代码简洁性和执行效率。它适用于多种场景,如缓存计算结果和数据结构操作。
摘要由CSDN通过智能技术生成

在Java编程中,Map接口提供了一个便捷的方法computeIfAbsent,它可以用来从map中获取key对应的value。如果value不存在,就使用提供的Function创建一个新的value,然后存入map中,最后返回这个新创建的value
computeIfAbsent方法是Java 8中引入的一种简化操作Map的方式。该方法通过自动检查键值对是否存在并生成缺失的值,减少了手动检查和插入的样板代码。它不仅使代码更加简洁和易读,还提高了操作的效率和一致性。

computeIfAbsent 方法的简介

computeIfAbsent方法在Java 8中引入,用于简化在Map中获取值的操作。如果指定的键在Map中不存在,computeIfAbsent会调用指定的函数来生成一个新的值,并将其与键关联。这样,开发者不需要显式地检查键是否存在,从而减少了样板代码。

方法签名

default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)

参数说明

  • key:要在map中查找的键。
  • mappingFunction:用于生成默认值的函数。

返回值

  • 如果key已经存在于map中,则返回对应的value。
  • 如果key不存在于map中,则使用mappingFunction生成一个新value,存入map,并返回这个新value。

示例

优化前的代码

在没有使用computeIfAbsent方法之前,我们通常会这样写:

Map<String, Set<Pet>> statistics = new HashMap<>();
Set<Pet> pets = statistics.get(threadName);
if (pets == null) {
    pets = new HashSet<>();
    statistics.put(threadName, pets);
}
优化后的代码

使用computeIfAbsent方法后,代码变得更加简洁和易读:

Map<String, Set<Pet>> statistics = new HashMap<>();
Set<Pet> pets = statistics.computeIfAbsent(threadName, k -> new HashSet<>());

工作原理

default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
    Objects.requireNonNull(mappingFunction);
    V v;
    if ((v = get(key)) == null) {
        V newValue;
        if ((newValue = mappingFunction.apply(key)) != null) {
            put(key, newValue);
            return newValue;
        }
    }
    return v;
}

详细解释

  • 检查现有值:首先检查指定的键是否已经存在于map中。
  • 生成新值:如果键不存在,使用mappingFunction生成一个新的值。
  • 存储新值:将新生成的值与键关联并存储在map中。
  • 返回值:返回与键关联的值(新生成的或已存在的)。

实际应用中的示例

示例1:统计单词出现的次数

我们有一个文本,想统计每个单词出现的次数。我们可以使用computeIfAbsent方法来简化统计逻辑:

import java.util.*;

public class WordCounter {
    public static void main(String[] args) {
        String text = "hello world hello Java hello world";
        String[] words = text.split(" ");
        
        Map<String, Integer> wordCount = new HashMap<>();
        
        for (String word : words) {
            wordCount.computeIfAbsent(word, k -> 0);
            wordCount.put(word, wordCount.get(word) + 1);
        }
        
        wordCount.forEach((k, v) -> System.out.println(k + ": " + v));
    }
}

在这个例子中,computeIfAbsent方法确保每个单词在第一次出现时被初始化为0,然后我们简单地增加计数值。

示例2:分组学生名单

假设我们有一组学生的成绩记录,我们想按分数段对学生进行分组。例如,分数在90以上的分为一组,80-89分为一组,依此类推。我们可以使用computeIfAbsent方法来实现这个功能:

import java.util.*;

public class StudentGrouper {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
            new Student("Alice", 85),
            new Student("Bob", 92),
            new Student("Charlie", 87),
            new Student("David", 72),
            new Student("Eve", 90)
        );
        
        Map<String, List<String>> gradeGroups = new HashMap<>();
        
        for (Student student : students) {
            String gradeCategory = getGradeCategory(student.getScore());
            gradeGroups.computeIfAbsent(gradeCategory, k -> new ArrayList<>()).add(student.getName());
        }
        
        gradeGroups.forEach((k, v) -> System.out.println(k + ": " + v));
    }
    
    public static String getGradeCategory(int score) {
        if (score >= 90) {
            return "90-100";
        } else if (score >= 80) {
            return "80-89";
        } else if (score >= 70) {
            return "70-79";
        } else {
            return "Below 70";
        }
    }
}

class Student {
    private String name;
    private int score;
    
    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }
    
    public String getName() {
        return name;
    }
    
    public int getScore() {
        return score;
    }
}

在这个示例中,computeIfAbsent方法确保每个分数段(例如“90-100”)被正确初始化为一个新的ArrayList,然后我们将学生的名字添加到对应的分组中。

示例3:构建依赖图

假设我们有一组任务,每个任务可能依赖于其他任务。我们希望构建一个依赖图,表示每个任务的依赖关系。我们可以使用computeIfAbsent方法来简化图的构建:

import java.util.*;

public class DependencyGraph {
    public static void main(String[] args) {
        Map<String, List<String>> dependencies = new HashMap<>();
        
        addDependency(dependencies, "Task1", "Task2");
        addDependency(dependencies, "Task1", "Task3");
        addDependency(dependencies, "Task2", "Task4");
        addDependency(dependencies, "Task3", "Task4");
        addDependency(dependencies, "Task4", "Task5");
        
        dependencies.forEach((k, v) -> System.out.println(k + " depends on " + v));
    }
    
    public static void addDependency(Map<String, List<String>> dependencies, String task, String dependency) {
        dependencies.computeIfAbsent(task, k -> new ArrayList<>()).add(dependency);
    }
}

在这个示例中,computeIfAbsent方法确保每个任务都有一个对应的依赖列表。如果任务不存在,则初始化一个新的ArrayList并添加依赖关系。

示例4:缓存计算结果

在某些场景中,计算某些值可能非常耗时,因此我们希望缓存计算结果以提高效率。我们可以使用computeIfAbsent方法来实现简单的缓存:

import java.util.*;

public class FibonacciCache {
    private static Map<Integer, Integer> cache = new HashMap<>();
    
    public static void main(String[] args) {
        System.out.println(fibonacci(10)); // 输出:55
        System.out.println(fibonacci(20)); // 输出:6765
        System.out.println(fibonacci(30)); // 输出:832040
    }
    
    public static int fibonacci(int n) {
        if (n <= 1) {
            return n;
        }
        
        return cache.computeIfAbsent(n, k -> fibonacci(k - 1) + fibonacci(k - 2));
    }
}

在这个示例中,computeIfAbsent方法用于缓存斐波那契数列的计算结果。对于每一个n,如果缓存中不存在对应的值,则进行计算并缓存结果。这种方法大大提高了计算效率,避免了重复计算。

优势总结

使用computeIfAbsent方法有以下几个优势:

  1. 简洁性:减少了样板代码,使代码更加简洁和易读。
  2. 避免重复代码:通过使用computeIfAbsent方法,我们避免了显式的空检查和插入逻辑。
  3. 线程安全性:对于某些并发Map实现(如ConcurrentHashMap),computeIfAbsent提供了线程安全的方式来处理映射关系。
  4. 性能提升:在需要缓存计算结果或避免重复计算的场景中,computeIfAbsent可以显著提高性能。
  5. 代码一致性:通过使用computeIfAbsent,代码更加一致和规范,易于维护。

通过理解和使用computeIfAbsent方法,开发者可以写出更简洁、易读且高效的代码,使得在操作map时更加得心应手。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值