我有一个String[]
dataValues
,如下所示:
ONE:9
TWO:23
THREE:14
FOUR:132
ONE:255
TWO:727
FIVE:3
THREE:196
FOUR:1843
ONE:330
TWO:336
THREE:190
FOUR:3664
我想总计ONE
,TWO
,THREE
,FOUR
,FIVE
的值。
所以我为同一个创建了HashMap
:
Map<String, Integer> totals = new HashMap<String, Integer>();
for(String dataValue : dataValues){
String[] keyVal = dataValue.split(":");
totals.put(keyVal[0], totals.get(keyVal[0]).intValue() + Integer.parseInt(keyVal[1]));
}
但如果地图上尚未存在该密钥,则上面的代码显然会抛出以下异常:
Exception in thread "main" java.lang.NullPointerException
在上面的用例中获取总计的最佳方法是什么?
答案 0 :(得分:5)
您可以获取给定键的值并检查它是否为空:
for(String dataValue : dataValues){
String[] keyVal = dataValue.split(":");
Integer i = totals.get(keyVal[0]);
if(i == null) {
totals.put(keyVal[0], Integer.parseInt(keyVal[1]));
} else {
totals.put(keyVal[0], i + Integer.parseInt(keyVal[1]));
}
}
在上面的用例中获取总计的最佳方法是什么?
使用Java 8,您可以使用合并功能
for(String dataValue : dataValues){
String[] keyVal = dataValue.split(":");
totals.merge(keyVal[0], Integer.parseInt(keyVal[1]), Integer::sum);
}
这个功能有什么作用?让我们引用文档:
如果指定的键尚未与值关联或是 与null关联,将其与给定的非null值相关联。 否则,将相关值替换为给定的结果 重新映射函数,如果结果为空则删除
因此,当你得到它时,如果没有与该键相关联的值,则只需将其映射为keyVal[1]
的int值。如果已经存在,则需要提供一个函数来决定对两个值(已映射的值和要映射的值)执行的操作。
在你的情况下你想要求它们,所以这个函数看起来像(a, b) -> a + b
,可以用方法引用Integer.sum
代替,因为它是一个带两个int并返回一个int的函数,所以一个有效的候选人(当然还有你需要的语义)。
<小时/> 但是等等,我们实际上可以做得更好!这就是Stream API和收集器类的用武之地。
从文件中获取Stream<String>
,将每一行拆分为一个数组,按每个数组的第一个元素(键)对每个数组进行分组,将其第二个元素(值)映射为整数并对它们求和:
import static java.util.stream.Collectors.*;
...
Map<String, Integer> map = Files.lines(Paths.get("file"))
.map(s -> s.split(":"))
.collect(groupingBy(arr -> arr[0], summingInt(arr -> Integer.parseInt(arr[1])));
另一种方法是使用toMap
收集器。
.collect(toMap(arr -> arr[0], arr -> Integer.parseInt(arr[1]), Integer::sum));
在相同的Stream<String[]>
中,您会在Map<String, Integer>
中收集密钥为arr[0]
的结果,其值为arr[1]
所持有的int值。如果您具有相同的键,则通过将它们相加来合并值。
两者都给出相同的结果,我喜欢第一个结果,因为使用收集器的名称,它使得意图明确表示您正在对元素进行分组,但这取决于您选择。
一开始可能有点难以理解,但是一旦你掌握了这些(下游)收藏家的概念,它就会非常强大。
希望它有所帮助! :)
答案 1 :(得分:4)
由于Java 8而不是map.get
,您可以使用map.getOrDefault
,如果缺少数据,将返回您定义的默认数据
totals.getOrDefault(keyVal[0], 0).intValue()
答案 2 :(得分:3)
这是一个优雅的(编辑:pre Java 8)解决方案:
Integer storedVal = hashMap.get(str);
String str = keyVal[0];
int num = Integer.parseInt(keyVal[1]);
hashMap.put(str, storedVal == null ? num : storedVal + num);
检查密钥是否存在。如果没有,请使用保持的int。
创建它如果密钥确实存在,则检索该值并进行数学运算,存储总和。
这是有效的,因为如果一个键已经存在,'put'将覆盖该值。