java.util.Map getOrDefault的陷阱

深入探讨Java8中Map.getOrDefault()方法的使用误区,分析其与预期不符的行为,尤其是在处理null值时可能导致的NullPointerException问题,并对比MapUtils.getString()的安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近使用Java 8新增加的java.util.Map.getOrDefault()方法,结果却发现是一个大坑。

先上代码。

Map<String, String> map = Maps.newHashMap();
map.put("test", null);
System.out.println(map.getOrDefault("test", "default"));
System.out.println(map.getOrDefault("test", "default") == null);
System.out.println(org.apache.commons.collections4.MapUtils.getString(map, "test", "default"));

再看执行结果。

接下来开始分析。根据方法getOrDefault(Object key, V defaultValue),我天真地认为该方法是先从Map中get(key),如果获取到的值为null,那么就会取defaultValue,类似于org.apache.commons.collections4.MapUtils.getString(final Map<? super K, ?> map, final K key, final String defaultValue)。直到使用过后遇到了NPE时,我才认真看了下源码,源码如下。

源码的这个逻辑不是一般得坑人啊!从Map中get(key)的值不为null或者包含key时,就返回get(key)的值。但是这里有一个问题,Map中包含某个key时,该key对应的值也是可以为null的!本来想用getOrDefault来避免null并设置默认值的,结果还是有可能返回null并可能造成NPE问题。

结论:java.util.Map.getOrDefault() 方法并不能很贴切实际业务的使用,还是使用MapUtils.getXxx(final Map<? super K, ?> map, final K key, final Xxx defaultValue)来安全地获取非null值吧!

<think>好的,我需要帮助用户找到用Java删除字符串中出现次数最少的字符的方法,并且保留原有顺序。首先,我得理解用户的需求。他们想处理一个字符串,找出出现次数最少的字符,然后删除所有这些字符,同时保持其他字符的顺序不变。那怎么开始呢? 首先,我应该考虑如何统计每个字符的出现次数。在Java中,可以用HashMap来统计字符频率。遍历字符串的每个字符,将它们作为键存入HashMap,值是该字符出现的次数。这一步应该没问题,不过需要注意字符的大小写是否敏感?用户没说,假设是区分大小写,否则需要统一转成小写或大写。但题目没说明,可能默认保留原样。 接下来,找到最小的出现次数。遍历HashMap的值,找到最小值。如果有多个字符都有同样的最小次数,都需要被删除。例如,如果有字符a出现1次,字符b也出现1次,那么两者都要删除。 然后,需要构造结果字符串,排除所有出现次数等于最小值的字符,同时保持顺序。原始字符串的顺序必须保留,所以不能直接处理HashMap,而是需要再次遍历原始字符串,逐个字符检查其出现次数是否大于最小值,如果是,则保留,否则跳过。 那具体步骤应该是: 1. 统计字符频率:用HashMap<Character, Integer>。 2. 找出最小值。 3. 遍历原字符串,构建结果字符串,只保留出现次数大于最小值的字符。 可能的陷阱:如果所有字符的出现次数相同,比如每个字符都出现一次,那么结果就是空字符串。例如输入"abcd",输出应该是空。 现在,如何实现呢? 代码的大致结构: public static String removeLeastFrequent(String s) { // 统计频率 Map<Character, Integer> freq = new HashMap<>(); for (char c : s.toCharArray()) { freq.put(c, freq.getOrDefault(c, 0) + 1); } // 找出最小值 int min = Collections.min(freq.values()); // 构建结果 StringBuilder sb = new StringBuilder(); for (char c : s.toCharArray()) { if (freq.get(c) != min) { sb.append(c); } } return sb.toString(); } 这样应该可以。但需要考虑特殊情况,比如空字符串?比如输入为null或者空的情况,可能需要处理,但用户可能希望处理有效输入。 测试案例: 比如输入"abcaabbcc",统计频率:a出现3次,b出现3次,c出现3次,那么最小值是3,所有字符都保留,结果不变? 或者可能我哪里搞错了。比如假设输入是"aaabbbcc",那么a出现3,b出现3,c出现2,最小值是2,所以删除c。输入字符串中的c都会被删除。 例如输入"abbccc",统计各字符次数:a:1,b:2,c:3。最小次数是1,所以删除a。结果变成"bbccc"。 那这段代码应该可以处理这些情况。 那用户的问题可能解决了。不过用户还提到参考引用里的内容,比如引用[1]提到了用trim和split,可能无关,但用户可能希望用类似的方法处理字符串。不过这里的问题不需要处理空格,只是删除特定字符。可能不需要trim。 另外,用户可能想处理出现次数最少的所有字符,比如如果有多个字符都是出现次数最少的,都要删除。例如输入"abcdd",其中a、b、c出现1次,d出现2次。那么最小值是1,这三个字符都会被删除,结果为"dd"。 代码中的逻辑是正确的,因为会检查每个字符的频率是否等于最小值,如果是则跳过。 现在,有没有可能优化代码?比如当所有字符的出现次数都相同时,比如输入"aabb",每个字符出现两次,那么结果为空。这应该是正确的。 现在,用户可能还需要考虑效率,但这个问题的时间复杂度是O(n),两次遍历,应该足够高效。 综上,这个代码应该满足用户的需求。现在需要将思路整理成步骤,用中文解释清楚,并给出代码示例。</think>### 分步实现方法 #### 步骤1:统计字符出现频率 使用`HashMap`记录字符串中每个字符的出现次数。遍历字符串,逐个字符统计: ```java Map<Character, Integer> frequencyMap = new HashMap<>(); for (char c : inputStr.toCharArray()) { frequencyMap.put(c, frequencyMap.getOrDefault(c, 0) + 1); } ``` #### 步骤2:确定最小出现次数 通过`Collections.min()`方法获取所有频率中的最小值: ```java int minFrequency = Collections.min(frequencyMap.values()); ``` #### 步骤3:构建结果字符串 再次遍历原字符串,仅保留出现次数大于最小值的字符,使用`StringBuilder`提高效率: ```java StringBuilder result = new StringBuilder(); for (char c : inputStr.toCharArray()) { if (frequencyMap.get(c) != minFrequency) { result.append(c); } } return result.toString(); ``` ### 完整代码示例 ```java import java.util.Collections; import java.util.HashMap; import java.util.Map; public class RemoveLeastFrequentChar { public static String removeLeastFrequent(String str) { if (str == null || str.isEmpty()) return str; Map<Character, Integer> frequencyMap = new HashMap<>(); for (char c : str.toCharArray()) { frequencyMap.put(c, frequencyMap.getOrDefault(c, 0) + 1); } int minFrequency = Collections.min(frequencyMap.values()); StringBuilder result = new StringBuilder(); for (char c : str.toCharArray()) { if (frequencyMap.get(c) != minFrequency) { result.append(c); } } return result.toString(); } public static void main(String[] args) { String input = "abbccc"; System.out.println(removeLeastFrequent(input)); // 输出: bbbccc } } ``` ### 关键点说明 1. **时间复杂度**:$O(n)$,两次遍历字符串,一次遍历频率值,效率较高[^1]。 2. **空间复杂度**:$O(k)$,$k$为字符串中不同字符的数量。 3. **保留顺序**:通过第二次遍历原字符串而非直接操作集合,保证字符顺序不变[^2]。 ### 特殊情况处理 - 若所有字符出现次数相同(如`"aabbcc"`),返回空字符串。 - 输入为空时直接返回原值,避免空指针异常。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值