JDK8 应该是 Java 中最坚挺一个版本,这个版本新增不少特性,让咱们开发起来多了不少便利。java
不过最近 Review 项目代码的时候发现,虽然不少项目工程已经使用了 JDK8,可是工程代码却不多使用到 JDK8 新特性、新方法。app
若是单从代码正确性上来讲,老方式写法写固然没有什么问题,那惟一的缺点其实就是代码行数比较多,比较繁琐。框架
那一样的需求,使用 JDK8 新方法,其实几行代码就能够搞定,这样代码就会变得很是简洁。ide
今天就以三个比较常见的场景为例,教你几招,使用 JDK8 Map
新增的方法简化代码开发。函数
下面就来看看此次即将用到 Map
几个新方法:工具
欢迎关注个人公众号:小黑十一点半,得到平常干货推送。若是您对个人专题内容感兴趣,也能够关注个人博客:studyidea.cn编码
平常开发中咱们一般会从 Map
获取元素,而后进行相关的业务处理,示例代码以下:idea
Map<String, String> map = new HashMap(); map.put("公号", "小黑十一点半"); map.put("主理人", "楼下小黑哥"); // 可能存在 NPE 问题 System.out.println(map.get("支付").toUpperCase()); 复制代码
若是就像示例代码直接处理,一旦 Map
中相应元素不存在,那么咱们就会碰到空指针问题。spa
为了解决这个问题,一般咱们能够先判断一下元素是否为 null
,若是不为 null
,再作相应的业务处理。指针
// 第一种 if 判空 String value = map.get("支付"); if (!Objects.isNull(value)) { System.out.println(value.toUpperCase()); } 复制代码
这种方式惟一劣势就是代码处理上比较繁琐,不是很简洁。
因此针对这种状况,其实可使用条件运算符,设置一个默认空值,从而避免后续处理发生空指针。
// 第一种 if 判空 String value = map.get("支付"); // 第二种 条件运算符 value = Objects.isNull(value) ? "" : value; 复制代码
这种方式比较简洁,因此平常开发中我比较喜欢用这种方式。
ps: 这里的前提,空字符串对于业务没有特殊意义。若是存在特殊意义,那就不能使用这种方式了。
那若是使用 JDK8 ,其实就很方便了,咱们就可使用 Map#getOrDefault
直接代替条件运算符。
// 等同于条件运算符的效果: Objects.isNull(value) ? "" : value; String value = map.getOrDefault("支付",""); 复制代码
借助 Map#getOrDefault
一行代码直接搞定,就是这么简单。
若是你还在使用 JDK8 以前的版本,没办法使用这个方法。不要紧,咱们能够借助 Apache Common-Lang3 提供的工具类 MapUtils
避免空指针。
// Apache MapUtils String value = MapUtils.getString(map, "支付", ""); 复制代码
MapUtils
这个工具类相对于Map#getOrDefault
有一个好处,针对传入 Map
为 null
的状况,能够设置默认值。
假设咱们是从 POJO
对象获取 Map
参数,这个时候为了防止空指针,咱们就须要提早作一个空指针的判断。
不过若是使用 MapUtils
,那咱们就不须要判断是否为 null
,方法内部已经封装这个逻辑。
MapUtils.getString(pojo.getMap(),"支付", ""); 复制代码
平常开发中,咱们会碰到这类场景,须要一个键须要映射到多个值,这个时候咱们可使用 Map<K, List<V>>
这个结构。
此时添加元素的时候,咱们须要作一些判断,当内部元素不存在时候主动建立一个集合对象,示例代码以下:
Map<String, List<String>> map = new HashMap(); List<String> classify = map.get("java框架"); if (Objects.isNull(classify)) { classify = new ArrayList<>(); classify.add("Spring"); map.put("java框架", classify); } else { classify.add("Spring"); } 复制代码
上面的代码比较繁琐,到了 JDK8,Map
新增一个 computeIfAbsent
方法:
default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) { 复制代码
若是 Map
中 key
对应的 value
不存在,则会将 mappingFunction
计算产生的值做为保存为该 key
的 value
,而且返回该值。不然不做任何计算,将会直接返回 key
对应的 value。
利用这个特性,咱们能够直接使用 Map#computeIfAbsent
一行代码完成上面的场景,示例代码以下:
map.computeIfAbsent("java框架", key -> new ArrayList<>()).add("Spring"); 复制代码
那其实 Map
中还有一个方法 putIfAbsent
,功能跟 computeIfAbsent
比较相似。
那刚开始使用的时候,误觉得可使用 putIfAbsent
完成上面的需求:
// ERROR:会有 NPE 问题 map.putIfAbsent("java框架", new ArrayList<>()).add("Spring"); 复制代码
那其实这是错误的,当 Map
中 key
对应 value
不存在的时候,putIfAbsent
将会直接返回 null
。
而 computeIfAbsent
将会返回 mappingFunction
计算以后的值,像上面的场景直接返回就是 new ArrayList
。
这一点须要注意一下,切勿用错方法,致使空指针。
最后针对上面这种一个键须要映射到多个值,其实还有一个更优秀的解决办法,使用 Google Guava 提供的新集合类型 Multiset
,以此快速完成一个键须要映射到多个值的场景。
示例代码以下:
ArrayListMultimap<Object, Object> multiset= ArrayListMultimap.create();
multiset.put("java框架","Spring"); multiset.put("java框架","Mybatis"); // java框架--->Spring,Mybatis 复制代码
假设有以下需求,咱们须要统计一段文字中相关单词出现的次数。那实现方式其实很简单,使用 Map
存储相关单词的次数便可,示例代码以下:
Map<String, Integer> countMap = new HashMap(); Integer count = countMap.get("java"); if (Objects.isNull(count)) { countMap.put("java", 1); } else { countMap.put("java", count++); } 复制代码
这类代码是否是很熟悉?一样比较繁琐。
接下来咱们可使用 JDK8 Map
新增方法进行改造,此次使用上面用过的 getOrDefault
再加 put
方法快速解决,示例代码以下:
// getOrDefault Integer count = countMap.getOrDefault("java",0); countMap.put("java", count + 1); 复制代码
那其实咱们还有一种办法,此次咱们使用 Map#merge
这个新方法,一句代码完成上述需求,示例代码以下:
countMap.merge("java", 1, Integer::sum); 复制代码
说真的,刚看到 merge
这个方法的时候仍是有点懵,尤为后面直接使用 lambda
函数,让人不是很好理解。
这里先将lambda
函数还原成正常类,给你们着重解释一下这个方法:
countMap.merge("java", 1, new BiFunction<Integer, Integer, Integer>() { @Override public Integer apply(Integer oldValue, Integer newValue) { return Integer.sum(oldValue,newValue); } }); 复制代码
用上面代码说明一下merge
方法,若是 java
这个值在 countMap
中不存在,那么将会其对应的 value
设置为 1。
那若是 java
在 countMap
中存在,则会调用第三个参数 remappingFunction
函数方法进行计算。
remappingFunction
函数中,oldValue
表明原先 countMap
中 java
的值,newValue
表明咱们设置第二个参数 1,这里咱们将二者相加,恰好完成累加的需求。
此次主要从我的平常碰到三个场景出发,给你们对比了一下使用 JDK8 Map
新增方法只会,二者代码区别。
从上面能够很明显看出,使用新增方法以后,咱们能够用不多的代码能够完成,总体看起来变得很是简洁。
不过 JDK8 以后不少方法都会用到 lambda
函数,不熟悉的话,其实比较难以理解代码。
不过也还好,咱们只要在平常编码过程当中,刻意去练习使用,很快就能上手。