作者| 沉默王二

责编| Carol

封图| CSDN│下载于视觉中国

从 10 年前我开始写第一行 Java 代码至今,一直觉得 null 在 Java 中是一个最特殊的存在,它既是好朋友,可以把不需要的变量置为 null 从而释放内存,提高性能;它又是敌人,因为它和大名鼎鼎且烦不胜烦的 NullPointerException(NPE)如影随形,而 NPE 的发明人 Tony Hoare 曾在 2009 年承认:“Null References 是一个荒唐的设计,就好像我赌输掉了十亿美元”。

你看,null 竟然是一个亦敌亦友的家伙。

通常,为了表示列表中的元素不存在,我们首先想到的就是返回 null,这种想法很合理,合理到无法反驳。我们来模拟一个实际的应用场景,假设作者现在要从数据库中获取一个姓名的列表,然后将姓名打印到控制台,对应的代码如下。

public class NullDemo {public static void main(String[] args) {List<String> names = getNamesFromDB();if (names != null) {for (String name : names) {System.out.println(name);}}}public static List<String> getNamesFromDB() {// 模拟此时没有从数据库获取到对应的姓名。return null;}
}

由于 getNamesFromDB() 方法返回了 null 来作为没有姓名列表的标志,那就意味着在遍历列表的时候要先对列表判空,否则将会抛出 NPE 错误,不信你把 if (names != null) 去掉试试,立马给你颜色看。

Exception in thread "main" java.lang.NullPointerExceptionat com.cmower.dzone.stopdoing3things.NullDemo.main(NullDemo.java:12)

那假如作者在遍历的时候不想判空又不想代码抛出 NPE 错误,他该怎么做呢?闭上你的大眼睛好好想一想。

嗯,报告,我想出来了,建议作者从数据库中获取姓名的时候返回长度为 0 的列表,来表示未找到数据的情况。代码示例如下所示:

public class Null2Length0Demo {public static void main(String[] args) {List<String> names = getNamesFromDB();for (String name : names) {System.out.println(name);}}public static List<String> getNamesFromDB() {// 模拟此时没有从数据库获取到对应的姓名。return Collections.emptyList();}
}

注:Collections.emptyList() 用于返回一个不可变的空列表,能理解吧?假如不能理解的话,我再写一个返回可变的空列表的示例,你对比着感受一下就理解了。

public class Null2Length0MutableDemo {public static void main(String[] args) {List<String> names = getNamesFromDB();for (String name : names) {System.out.println(name);}}public static List<String> getNamesFromDB() {// 模拟此时没有从数据库获取到对应的姓名。return new ArrayList<>();}
}

new ArrayList<>() 返回的就是可变的,意味着你还可以改变这个列表的元素,比如说增加,删除是不可能的了,因为本身就没有元素可删。

你看,Collections.emptyList() 和 new ArrayList<>() 都可以替代 null,来减少打印列表时不必要的判空以及那个讨厌的家伙——NPE。

除了我这个想法之外,你还能想到其他的解决方案吗?来,再次闭上你的大眼睛,替作者想一想,没准你还能想到一个—— Java 8 新增的 Optional 类,一个容器类,可以存放任意类型的元素,如果值存在则
isPresent() 方法会返回 true;Optional 类提供了很多专业的方法而不用显式进行空值检查,从而巧妙地消除了 NPE。

来,先读示例为快!

public class Null2OptionalDemo {public static void main(String[] args) {Optional<List<String>> list = getNamesFromDB();list.ifPresent(names -> {for (String name : names) {System.out.println(name);}});}public static Optional<List<String>> getNamesFromDB() {boolean hasName = true;if (hasName) {String [] names = {"沉默王二", "一枚有趣的程序员", "微信搜索关注我"};return Optional.of(Arrays.asList(names));}return Optional.empty();}
}

看得不太懂?我来负责任地介绍一下,你们握个手。

假如数据库中存在姓名,则使用 Optional.of() 对返回值进行包装,从而返回一个 Optional 类型的对象。为什么不用构造方法呢,因为构造方法是 private 的(源码如下所示)。

private Optional(T value) {this.value = value;
}

那为什么要用 Optional.of() 呢?嗯,good question。继续上源码。

public static <T> Optional<T> of(T value) {return new Optional<>(Objects.requireNonNull(value));
}

1)如果 value 为 null,那么 Objects.requireNonNull(value) 就会抛出 NPE(嗯哼,总归是要碰面的,但好歹不用我们程序员主动 check 了)。

2)如果 value 不为 null,则通过 new 关键字创建正常的 Optional 对象。

假如数据库中不存在姓名呢?使用 Optional.empty() 作为返回值。来,继续上源码。

public static<T> Optional<T> empty() {@SuppressWarnings("unchecked")Optional<T> t = (Optional<T>) EMPTY;return t;
}

嗯哼,EMPTY 是什么玩意?

private static final Optional<?> EMPTY = new Optional<>(null);

竟然是 Optional 类的一个私有常量(static + final)。怎么此刻我的脑子里想起了安徒生先生的寓言故事——皇帝的新衣,嗯,甭管了,反正“底层终究是丑陋的”。

这样的话,就可以使用 Optional 对象的 ifPresent() 方法来判断值是否存在,如果只需要处理值存在的情况,就可以使用 Lambda 表达式的方式直接打印姓名。

list.ifPresent(names -> {for (String name : names) {System.out.println(name);}
});

有点简单粗暴,对不对?但不管怎么说,终于可以在表象上和 null,NPE 说拜拜了,做人嘛,开心点~

如果你有其他想法,欢迎在评论区和我们交流!

《原力计划【第二季】- 学习力挑战》正式开始!即日起至 3月21日,千万流量支持原创作者!更有专属【勋章】等你来挑战

推荐阅读:不看就亏系列!这里有完整的 Hadoop 集群搭建教程,和最易懂的 Hadoop 概念!| 附代码
时间复杂度的表示、分析、计算方法……一文带你看懂时间复杂度!
30万行数据,Python 分析科比二十年职业生涯 | 原力计划
谈论新型冠状病毒、比特币、苹果公司……沃伦•巴菲特受访中的 18 个金句,值得一看!
一张图对比阿里、腾讯复工的区别
Python数据清理终极指南(2020版)
真香,朕在看了!

如何与亦敌亦友的 null 说拜拜?大神原来是这么做的!相关推荐

  1. 亦敌亦友 微软Edge浏览器为何要采用Chrome引擎?

    微软早在2015年就发布了Edge网络浏览器.但却在2018年出人意料地转而采用谷歌的Chromium开源引擎.本文就微软如何做出这一重大决定以及接下来可能发生什么的故事进行了描述.微软首席执行官萨蒂 ...

  2. 抚仙湖,一个亦梦亦幻的地方,这个五一节,我们骑友′的诗和远方

    云南省玉溪市抚仙湖是中国南方最大的深水型淡水湖泊之一,位于云南省中部,距离昆明市约80公里.抚仙湖的面积约为212平方公里,平均水深约为120米,最大水深可达157米. 抚仙湖最美的景点有很多,其中最 ...

  3. 敏捷与 DevOps:是敌是友?

    敏捷与 DevOps:是敌是友? DevOps 是敏捷应用于软件团队的成果.但真正的问题是,在一场比赛中,哪一方会获胜? 在角斗场的一头,我们有经过认证的敏捷教练,他的朋友们都知道他是一个极限程序员, ...

  4. Docker与Kubernetes,是敌是友?

    本文讲的是Docker与Kubernetes,是敌是友?[编者的话]本文为读者提供了容器技术平台的组成说明,介绍了Docker公司的历史,编排框架Kubernetes推动Docker容器的使用,容器技 ...

  5. 虚虚实实,亦假亦真的 ValueTuple,绝对能眩晕你

    一:背景 1. 讲故事 前几天在写一个api接口,需要对衣物表进行分页查询,查询的output需要返回两个信息,一个是 totalCount,一个是 clothesList,在以前我可能需要封装一个 ...

  6. android 沉浸式_【沉浸式体验】投影秀科技与视觉:体验亦真亦幻的超常感受

    沉浸式投影作为一种新型的交互方式 受大众关注 全面覆盖观众视角 展现给参与者带来了亦真亦幻的超常感受 为参与者带来身临其境的体验感 投影秀科技与视觉+美学的结合 让你的活动与众不同 一起体验投影秀的魅 ...

  7. 我与小娜(04):时空变换,亦真亦幻

    我与小娜(04):时空变换,亦真亦幻       2月5日,我赶回南京浦口车站,从车站小件寄存处把"小口袋"领出来.对着"小口袋"拍了一下,小娜从里面把紧紧闭着 ...

  8. 用友T3标准版十大亮点展示

    用友T3标准版十大亮点探讨学习 用友标志 系统管理                        T3客户端 财务管理部分主要功能 1.建账 根据自己的需要建立账务,

  9. 大神note3千元指纹机,这是要逼疯友商吗

    新发现(光山居士).7月20日下午.奇酷公司在北京奥雅会展中心召开公布会,宣布推出首款千元级别的指纹识别机大神Note3.据悉.该型号手机.移动版售价899元.全网通版售1099元,并在16:00開始 ...

  10. 亦师亦友——忆我在北邮四年中的几位老师(全)

    发一篇本科毕业时候回忆本科阶段的一些老师的文字. --------------------------------------------------------------------------- ...

最新文章

  1. python rbf神经网络_原创,基于径向基函数(RBF)神经网络RBF网络的举例应用!
  2. 盘点VS2015 预览版的5个新特性
  3. python扫雷代码_谁说Python不能做游戏的?能做这些游戏,附赠所有游戏源码文件...
  4. Ubuntu 设置程序开机启动(以指定用户身份)
  5. java 常用流_Java流类图结构: 流的概念和作用流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数...
  6. java堆排序解决topk问题,详解堆排序解决TopK问题
  7. android网页声音大小设置在哪里,怎样调节网页声音的大小
  8. 分布式事务各方案对比分析
  9. 乐观锁实现之CAS算法分析
  10. 有监督学习和无监督学习
  11. CSDN好的blog
  12. 从限定词开始 - 词性识别在人工智能自然语言处理中的不足与改进
  13. 给你个使用NAS私有云服务器的理由
  14. Windows如何彻底删除.sys后缀的流氓文件
  15. 佛祖保佑注释代码(内含神兽与美女)
  16. 有互联网药品信息服务资格证是否可以销售药品?
  17. 个人收款平台 XorPay 对比 Payjs
  18. iOS开发之Unity游戏在iOS平台运行调研(踩坑)
  19. 微信壁纸小程序V1.2.0(自带后台上传图片)
  20. (十三)有一点心动 - 6

热门文章

  1. 兆骑科创创业赛事活动,投融资对接,活动路演
  2. java多线程编程详细入门教程
  3. win7桌面背景_win7桌面背景怎么改?
  4. 2020年最全易语言安装与配置使用教程
  5. 鸿蒙超级终端使用教程,超级终端怎么用(超级终端使用配置教程)
  6. Apache Ant安装与配置
  7. 使用 onpropertychange 和 oninput 检测 input、textarea输入改变
  8. 六句顺口溜教你速记100以内质数表
  9. 管理者必须要精通的六项管理技能
  10. catia三维轴承_基于CATIA的轴承三维参数化标准件库的开发