Java8 几个很好用的方法,真的很香

JDK8 应该是 Java 中最坚挺一个版本,这个版本新增很多特性,让我们开发起来多了很多便利。

不过最近 Review 项目代码的时候发现,虽然很多项目工程已经使用了 JDK8,但是工程代码却很少使用到 JDK8 新特性、新方法。

如果单从代码正确性上来说,老方式写法写当然没有什么问题,那唯一的缺点其实就是代码行数比较多,比较繁琐。

那同样的需求,使用 JDK8 新方法,其实几行代码就可以搞定,这样代码就会变得非常简洁。

今天就以三个比较常见的场景为例,教你几招,使用 JDK8 Map新增的方法简化代码开发。

下面就来看看这次即将用到 Map几个新方法:

预防空指针问题

日常开发中我们通常会从 Map获取元素,然后进行相关的业务处理,示例代码如下:

1Map<String, String> map = new HashMap(); 2map.put("公号", "小黑十一点半"); 3map.put("主理人", "楼下小黑哥"); 4// 可能存在 NPE 问题 5System.out.println(map.get("支付").toUpperCase());

如果就像示例代码直接处理,一旦 Map中相应元素不存在,那么我们就会碰到空指针问题。

为了解决这个问题,通常我们可以先判断一下元素是否为 null,如果不为 null,再做相应的业务处理。

1// 第一种 if 判空 2String value = map.get("支付"); 3if (!Objects.isNull(value)) { 4 System.out.println(value.toUpperCase()); 5}

这种方式唯一劣势就是代码处理上比较繁琐,不是很简洁。

所以针对这种情况,其实可以使用条件运算符,设置一个默认空值,从而避免后续处理发生空指针。

1// 第一种 if 判空 2String value = map.get("支付"); 3// 第二种 条件运算符 4value = Objects.isNull(value) ? "" : value;

这种方式比较简洁,所以日常开发中我比较喜欢用这种方式。

ps: 这里的前提,空字符串对于业务没有特殊意义。如果存在特殊意义,那就不能使用这种方式了。

那如果使用 JDK8 ,其实就很方便了,我们就可以使用 Map#getOrDefault直接代替条件运算符。

1// 等同于条件运算符的效果: Objects.isNull(value) ? "" : value; 2String value = map.getOrDefault("支付","");

借助 Map#getOrDefault 一行代码直接搞定,就是这么简单。

如果你还在使用 JDK8 之前的版本,没办法使用这个方法。没关系,我们可以借助 Apache Common-Lang3 提供的工具类 MapUtils 避免空指针。

1// Apache MapUtils 2String value = MapUtils.getString(map, "支付", "");

MapUtils这个工具类相对于Map#getOrDefault有一个好处,针对传入 Map为 null 的情况,可以设置默认值。

假设我们是从 POJO对象获取 Map 参数,这个时候为了防止空指针,我们就需要提前做一个空指针的判断。

不过如果使用 MapUtils,那我们就不需要判断是否为 null,方法内部已经封装这个逻辑。

MapUtils.getString(pojo.getMap(),"支付", ""); 

巧用 computeIfAbsent

日常开发中,我们会碰到这类场景,需要一个键需要映射到多个值,这个时候我们可以使用 Map<K, List<V>>这个结构。

此时添加元素的时候,我们需要做一些判断,当内部元素不存在时候主动创建一个集合对象,示例代码如下:

1Map<String, List<String>> map = new HashMap(); 2 3List<String> classify = map.get("java框架"); 4if (Objects.isNull(classify)) { 5 classify = new ArrayList<>(); 6 classify.add("Spring"); 7 map.put("java框架", classify); 8} else { 9 classify.add("Spring"); 10}

上面的代码比较繁琐,到了 JDK8,Map新增一个 computeIfAbsent方法:

1default V computeIfAbsent(K key, 2 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完成上面的需求:

1// ERROR:会有 NPE 问题 2map.putIfAbsent("java框架", new ArrayList<>()).add("Spring");

那其实这是错误的,当 Map 中 key 对应 value 不存在的时候,putIfAbsent将会直接返回 null。

而 computeIfAbsent将会返回 mappingFunction计算之后的值,像上面的场景直接返回就是 new ArrayList。

这一点需要注意一下,切勿用错方法,导致空指针。

最后针对上面这种一个键需要映射到多个值,其实还有一个更优秀的解决办法,使用 Google Guava 提供的新集合类型 Multiset,以此快速完成一个键需要映射到多个值的场景。

示例代码如下:

1ArrayListMultimap<Object, Object> multiset= ArrayListMultimap.create(); 2multiset.put("java框架","Spring"); 3multiset.put("java框架","Mybatis"); 4// java框架--->Spring,Mybatis

单词统计

假设有如下需求,我们需要统计一段文字中相关单词出现的次数。那实现方式其实很简单,使用 Map存储相关单词的次数即可,示例代码如下:

1Map<String, Integer> countMap = new HashMap(); 2Integer count = countMap.get("java"); 3if (Objects.isNull(count)) { 4 countMap.put("java", 1); 5} else { 6 countMap.put("java", count++); 7}

这类代码是不是很熟悉?同样比较繁琐。

接下来我们可以使用 JDK8 Map 新增方法进行改造,这次使用上面用过的 getOrDefault 再加 put 方法快速解决,示例代码如下:

1// getOrDefault 2Integer count = countMap.getOrDefault("java",0); 3countMap.put("java", count + 1);

那其实我们还有一种办法,这次我们使用 Map#merge这个新方法,一句代码完成上述需求,示例代码如下:

countMap.merge("java", 1, Integer::sum); 

说真的,刚看到 merge这个方法的时候还是有点懵,尤其后面直接使用 lambda 函数,让人不是很好理解。

这里先将lambda 函数还原成正常类,给大家着重解释一下这个方法:

1countMap.merge("java", 1, new BiFunction<Integer, Integer, Integer>() { 2 @Override 3 public Integer apply(Integer oldValue, Integer newValue) { 4 return Integer.sum(oldValue,newValue); 5 } 6});

用上面代码说明一下merge方法,如果 java这个值在 countMap中不存在,那么将会其对应的 value 设置为 1。

那如果 java 在 countMap 中存在,则会调用第三个参数 remappingFunction 函数方法进行计算。

remappingFunction 函数中,oldValue代表原先 countMap 中 java 的值,newValue代表我们设置第二个参数 1,这里我们将两者相加,刚好完成累加的需求。

最后

这次主要从个人日常碰到三个场景出发,给大家对比了一下使用 JDK8 Map 新增方法只会,两者代码区别。

从上面可以很明显看出,使用新增方法之后,我们可以用很少的代码可以完成,整体看起来变得非常简洁。

不过 JDK8 之后很多方法都会用到 lambda 函数,不熟悉的话,其实比较难以理解代码。

不过也还好,我们只要在日常编码过程中,刻意去练习使用,很快就能上手。

最后,JDK8 还有许多好用方法,刻意简化代码开发,你可以在留言区推荐几个吗?

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Java日期时间API系列31

  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )