Map中处理映射时的一个难点就是更新映射项,如果Map中没有指定key,就直接把value设为0,但是如果Map中如果有了指定key,就要把当前key关联value更新,并放回更新后的值。下面是一个例子:
键盘录入字符串,统计每个字符出现的次数
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请录入一个字符串:");
String line = sc.nextLine();
char[] chs = line.toCharArray();// 字符串转字符数组
Map<Character, Integer> map = new HashMap<>();// 字符数组中数据存入HashMap
for (char c : chs) {// 对每一个字符进行判断
if (!map.containsKey(c)) {// map中没有c键,说明第一次统计字符,设置key的value为1
map.put(c, 1);
} else {// map中有c键,说明不是第一次统计字符,把当前key的value设置为+1
map.put(c, map.get(c) + 1);
}
}
StringBuilder sb = new StringBuilder();
Set<Entry<Character, Integer>> entrySet = map.entrySet();// 用entrySet()得到Set对象
for (Entry<Character, Integer> entry : entrySet) {// 对每一个Set对象进行拼接
char ch = entry.getKey();
int num = entry.getValue();
sb.append(ch).append("出现了").append(num).append("次,");
}
System.out.println(sb.substring(0, sb.length() - 1));// 截取子串,清除最后一个逗号
}
在对char[ ] 数组遍历的foreach中,使用了if - else结构,其实还可以写成三元表达式:
for (char c : chs) {// 对每一个字符进行判断
/*if (!map.containsKey(c)) {// map中没有c键,说明第一次统计字符,设置key的value为1
map.put(c, 1);
} else {// map中有c键,说明不是第一次统计字符,把当前key的value设置为+1
map.put(c, map.get(c) + 1);
}*/
map.put(c, map.containsKey(c) ? map.get(c) + 1 : 1);
}
但是这个三元表达式其实没有针对刚刚的难点做出相应的优化,第一次出现key时依然取定值,重复出现key时依然要+ 1。那么有没有更优雅的代码呢?Java8的merge方法就是针对这种情况而设计的:
for (char c : chs) {// 对每一个字符进行判断
/*if (!map.containsKey(c)) {// map中没有c键,说明第一次统计字符,设置key的value为1
map.put(c, 1);
} else {// map中有c键,说明不是第一次统计字符,把当前key的value设置为+1
map.put(c, map.get(c) + 1);
}*/
// map.put(c, map.containsKey(c) ? map.get(c) + 1 : 1);
map.merge(c, 1, Integer::sum);
}
在这里,我们进一步省略了代码。Java8的API是这样介绍merge( )的:
-
-
-
如果指定的键尚未与值相关联或与null相关联,则将其与给定的非空值相关联。 否则,将关联值替换为给定重映射函数的结果,如果结果为default V merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)
null
。 当组合键的多个映射值时,该方法可能是有用的。 例如,要创建或附加String msg
到值映射:map.merge(key, msg, String::concat)
如果函数返回
null
,则删除映射。 如果函数本身引发(未检查)异常,则异常被重新引导,并且当前映射保持不变。
-
-
对于上面例子来说,这个方法其实是说:如果键原先不存在,
counts . merge ( c , 1 , Integer : : sum ) ;
将把 c 与 1 关联 , 否则使用 Integer :: sum 函数组合原值和 1 ( 也就是将原值与 1 求和 ) 。