Map中的新方法
相比 Collection,Map中加入了更多的方法!
forEach()
该方法签名为void forEach(BiConsumer<? super K,? super V> action),作用是对Map中的每个映射执行action指定的操作,其中BiConsumer是一个函数接口,里面有一个待实现方法void accept(T t, U u)。BinConsumer接口名字和accept()方法名字都不重要,请不要记忆他们。
需求:假设有一个数字到对应英文单词的Map,请输出Map中的所有映射关系.
Java7以及之前经典的代码如下:
// Java7以及之前迭代Map HashMap<Integer, String> map = new HashMap<>(); map.put(1, "one"); map.put(2, "two"); map.put(3, "three"); for(Map.Entry<Integer, String> entry : map.entrySet()){ System.out.println(entry.getKey() + "=" + entry.getValue()); }
使用Map.forEach()方法,结合匿名内部类,代码如下:
// 使用forEach()结合匿名内部类迭代Map HashMap<Integer, String> map = new HashMap<>(); map.put(1, "one"); map.put(2, "two"); map.put(3, "three"); map.forEach(new BiConsumer<Integer, String>(){ @Override public void accept(Integer k, String v){ System.out.println(k + "=" + v); } });
上述代码调用forEach()方法,并使用匿名内部类实现BiConsumer接口。当然,实际场景中没人使用匿名内部类写法,因为有Lambda表达式:
// 使用forEach()结合Lambda表达式迭代Map HashMap<Integer, String> map = new HashMap<>(); map.put(1, "one"); map.put(2, "two"); map.put(3, "three"); map.forEach((k, v) -> System.out.println(k + "=" + v)); }
getOrDefault()
该方法跟Lambda表达式没关系,但是很有用。方法签名为V getOrDefault(Object key, V defaultValue),作用是按照给定的key查询Map中对应的value,如果没有找到则返回defaultValue。使用该方法程序员可以省去查询指定键值是否存在的麻烦.
需求;假设有一个数字到对应英文单词的Map,输出4对应的英文单词,如果不存在则输出NoValue
// 查询Map中指定的值,不存在时使用默认值 HashMap<Integer, String> map = new HashMap<>(); map.put(1, "one"); map.put(2, "two"); map.put(3, "three"); // Java7以及之前做法 if(map.containsKey(4)){ // 1 System.out.println(map.get(4)); }else{ System.out.println("NoValue"); } // Java8使用Map.getOrDefault() System.out.println(map.getOrDefault(4, "NoValue")); // 2
putIfAbsent() 该方法跟Lambda表达式没关系,但是很有用。方法签名为V putIfAbsent(K key, V value),作用是只有在不存在key值的映射或映射值为null时,才将value指定的值放入到Map中,否则不对Map做更改.该方法将条件判断和赋值合二为一,使用起来更加方便.
remove()
我们都知道Map中有一个remove(Object key)方法,来根据指定key值删除Map中的映射关系;Java8新增了remove(Object key, Object value)方法,只有在当前Map中key正好映射到value时才删除该映射,否则什么也不做.
replace()
在Java7及以前,要想替换Map中的映射关系可通过put(K key, V value)方法实现,该方法总是会用新值替换原来的值.为了更精确的控制替换行为,Java8在Map中加入了两个replace()方法,分别如下:
replace(K key, V value),只有在当前Map中 key的映射存在时才用value去替换原来的值,否则什么也不做.
replace(K key, V oldValue, V newValue),只有在当前Map中 key的映射存在且等于oldValue时才用newValue去替换原来的值,否则什么也不做.
replaceAll() 该方法签名为replaceAll(BiFunction<? super K,? super V,? extends V> function),作用是对Map中的每个映射执行function指定的操作,并用function的执行结果替换原来的value,其中BiFunction是一个函数接口,里面有一个待实现方法R apply(T t, U u).不要被如此多的函数接口吓到,因为使用的时候根本不需要知道他们的名字.
需求:假设有一个数字到对应英文单词的Map,请将原来映射关系中的单词都转换成大写.
Java7以及之前经典的代码如下:
// Java7以及之前替换所有Map中所有映射关系 HashMap<Integer, String> map = new HashMap<>(); map.put(1, "one"); map.put(2, "two"); map.put(3, "three"); for(Map.Entry<Integer, String> entry : map.entrySet()){ entry.setValue(entry.getValue().toUpperCase()); }
使用replaceAll()方法结合匿名内部类,实现如下:
// 使用replaceAll()结合匿名内部类实现 HashMap<Integer, String> map = new HashMap<>(); map.put(1, "one"); map.put(2, "two"); map.put(3, "three"); map.replaceAll(new BiFunction<Integer, String, String>(){ @Override public String apply(Integer k, String v){ return v.toUpperCase(); } });
上述代码调用replaceAll()方法,并使用匿名内部类实现BiFunction接口。更进一步的,使用Lambda表达式实现如下:
// 使用replaceAll()结合Lambda表达式实现 HashMap<Integer, String> map = new HashMap<>(); map.put(1, "one"); map.put(2, "two"); map.put(3, "three"); map.replaceAll((k, v) -> v.toUpperCase());
简洁到让人难以置信.
merge()
该方法签名为merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction),作用是:
如果Map中key对应的映射不存在或者为null,则将value(不能是null)关联到key上;
否则执行remappingFunction,如果执行结果非null则用该结果跟key关联,否则在Map中删除key的映射.
参数中BiFunction函数接口前面已经介绍过,里面有一个待实现方法R apply(T t, U u).
merge()方法虽然语义有些复杂,但该方法的用方式很明确,一个比较常见的场景是将新的错误信息拼接到原来的信息上,比如:
map.merge(key, newMsg, (v1, v2) -> v1+v2);
compute()
该方法签名为compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction),作用是把remappingFunction的计算结果关联到key上,如果计算结果为null,则在Map中删除key的映射.
要实现上述merge()方法中错误信息拼接的例子,使用compute()代码如下:
map.compute(key, (k,v) -> v==null ? newMsg : v.concat(newMsg));
computeIfAbsent()
该方法签名为V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction),作用是:只有在当前Map中不存在key值的映射或映射值为null时,才调用mappingFunction,并在mappingFunction执行结果非null时,将结果跟key关联.
Function是一个函数接口,里面有一个待实现方法R apply(T t).
computeIfAbsent()常用来对Map的某个key值建立初始化映射.比如我们要实现一个多值映射,Map的定义可能是Map<K,Set >,要向Map中放入新值,可通过如下代码实现:
Map<Integer, Set<String>> map = new HashMap<>(); // Java7及以前的实现方式 if(map.containsKey(1)){ map.get(1).add("one"); }else{ Set<String> valueSet = new HashSet<String>(); valueSet.add("one"); map.put(1, valueSet); } // Java8的实现方式 map.computeIfAbsent(1, v -> new HashSet<String>()).add("yi");
使用computeIfAbsent()将条件判断和添加操作合二为一,使代码更加简洁.
computeIfPresent()
该方法签名为V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction),作用跟computeIfAbsent()相反,即,只有在当前Map中存在key值的映射且非null时,才调用remappingFunction,如果remappingFunction执行结果为null,则删除key的映射,否则使用该结果替换key原来的映射.
这个函数的功能跟如下代码是等效的:
// Java7及以前跟computeIfPresent()等效的代码 if (map.get(key) != null) { V oldValue = map.get(key); V newValue = remappingFunction.apply(key, oldValue); if (newValue != null) map.put(key, newValue); else map.remove(key); return newValue; } return null;
- END -
往期推荐
[
劲敌上线,PayPal成功入华,支付宝、微信的地位将受到威胁
[
Lambda表达式中Collections的接口有哪些变化?
[
开发Kafka消费者客户端需要注意哪些事项?
[
Kafka 中的分区器、序列化器、拦截器是否了解?它们之间的处理顺序是什么?
[
怎么理解Kafka消费者与消费组之间的关系?
本文分享自微信公众号 - 码农架构(iByteCoding)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。