Bendi新闻
>
别再用“! = null”做判空了!Optional更好用!

别再用“! = null”做判空了!Optional更好用!

10月前

👉 这是一个或许对你有用的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入芋道快速开发平台知识星球。下面是星球提供的部分资料: 

👉这是一个或许对你有用的开源项目

国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。

功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号、CRM 等等功能:

  • Boot 仓库:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • Cloud 仓库:https://gitee.com/zhijiantianya/yudao-cloud
  • 视频教程:https://doc.iocoder.cn
【国内首批】支持 JDK 21 + SpringBoot 3.2.2、JDK 8 + Spring Boot 2.7.18 双版本 

来源:waynblog


"Null 很糟糕." - Doug Lea。

Doug Lea 是一位美国的计算机科学家,他是 Java 平台的并发和集合框架的主要设计者之一。他在 2014 年的一篇文章中说过:“Null sucks.”1,意思是 null 很糟糕。他认为 null 是一种不明确的表示,它既可以表示一个值不存在,也可以表示一个值未知,也可以表示一个值无效。这样就会导致很多逻辑错误和空指针异常,给程序员带来很多麻烦。他建议使用 Optional 类来封装可能为空的值,从而提高代码的可读性和健壮性。

"发明 null 引用是我的十亿美元错误。" - Sir C. A. R. Hoare。

Sir C. A. R. Hoare 是一位英国的计算机科学家,他是快速排序算法、Hoare 逻辑和通信顺序进程等重要概念的发明者。他在 2009 年的一个软件会议上道歉说:“I call it my billion-dollar mistake. It was the invention of the null reference in 1965.”,意思是他把 null 引用称为他的十亿美元错误。他说他在 1965 年设计 ALGOL W 语言时,引入了 null 引用的概念,用来表示一个对象变量没有指向任何对象。他当时认为这是一个很简单和自然的想法,但后来发现这是一个非常糟糕的设计,因为它导致了无数的错误、漏洞和系统崩溃。他说他应该使用一个特殊的对象来表示空值,而不是使用 null。

自作者从事 Java 编程一来,就与 null 引用相伴,与 NullPointerException 相遇已经是家常便饭了。

null 引用是一种表示一个对象变量没有指向任何对象的方式,它是 Java 语言中的一个特殊值,也是导致空指针异常(NullPointerException)的主要原因。虽然 null 引用可以用来表示一个值不存在或未知,也可以用来节省内存空间。但是它也不符合面向对象的思想,因为它不是一个对象,不能调用任何方法或属性。

可以看到,null 引用并不好,我们应该尽量避免使用 null,那么我们该怎么避免 null 引用引起的逻辑错误和运行时异常嘞?

其实这个问题 Java 的设计者也知道,于是他们在 Java8 之后设计引入了 Optional 类解决这个问题,本文将给大家详细介绍下 Optional 类的设计目的以及使用方法。

Optional 类是什么?

Optional 类是 java 8 中引入的一个新的类,它的作用是封装一个可能为空的值,从而避免空指针异常(NullPointerException)。Optional 类可以看作是一个容器,它可以包含一个非空的值,也可以为空。Optional 类提供了一些方法,让我们可以更方便地处理可能为空的值,而不需要显式地进行空值检查或者使用 null。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

Optional 类的设计

Optional 类的设计是基于函数式编程的思想,它借鉴了 Scala 和 Haskell 等语言中的 Option 类型。Optional 类实现了 java.util.function 包中的 Supplier、Consumer、Predicate、Function 等接口,这使得它可以和 lambda 表达式或者方法引用一起使用,形成更简洁和优雅的代码。

Optional 类是一个不可变的类,它有两个子类:Optional.empty 和 Optional.of。Optional.empty 表示一个空的 Optional 对象,它不包含任何值。Optional.of 表示一个非空的 Optional 对象,它包含一个非空的值。我们可以使用这两个静态方法来创建 Optional 对象。例如:

// 创建一个空的 Optional 对象
Optional<String> empty = Optional.empty();

// 创建一个非空的 Optional 对象
Optional<String> hello = Optional.of("Hello");

注意,如果我们使用 Optional.of 方法传入一个 null 值,会抛出 NullPointerException。如果我们不确定一个值是否为空,可以使用 Optional.ofNullable 方法,它会根据值是否为空,返回一个相应的 Optional 对象。例如:

// 创建一个可能为空的 Optional 对象
Optional<String> name = Optional.ofNullable(getName());

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud
  • 视频教程:https://doc.iocoder.cn/video/

Optional 类的使用方法

Optional 类提供了一些方法,让我们可以更方便地处理可能为空的值,而不需要显式地进行空值检查或者使用 null。以下是一些常用的方法:

  • isPresent():判断 Optional 对象是否包含一个非空的值,返回一个布尔值。
  • get():如果 Optional 对象包含一个非空的值,返回该值,否则抛出 NoSuchElementException 异常。
// 使用 isPresent 和 get 方法
Optional<String> name = Optional.ofNullable("tom");
if (name.isPresent()) {
    System.out.println("Hello, " + name.get());
else {
    System.out.println("Name is not available");
}
// 输出:Hello tom
  • ifPresent(Consumer<? super T> action):如果 Optional 对象包含一个非空的值,执行给定的消费者操作,否则什么也不做。
// 使用 ifPresent(Consumer<? super T> action)
Optional<String> name = Optional.ofNullable("tom");
name.ifPresent(s -> {
    System.out.println("Hello, " + name.get());
});
// 输出:Hello tom
  • orElse(T other):如果 Optional 对象包含一个非空的值,返回该值,否则返回给定的默认值。
// 使用 orElse(T other)
Optional<String> name = Optional.ofNullable(null);
String greeting = "Hello, " + name.orElse("Guest");
System.out.println(greeting);
// 输出:Hello Guest
  • orElseGet(Supplier<? extends T> supplier):如果 Optional 对象包含一个非空的值,返回该值,否则返回由给定的供应者操作生成的值。
// 使用 orElseGet(Supplier<? extends T> supplier)
Optional<String> name = Optional.ofNullable(null);
String greeting = "Hello, " + name.orElseGet(() -> "Guset");
System.out.println(greeting);
// 输出:Hello Guset
  • orElseThrow(Supplier<? extends X> exceptionSupplier):如果 Optional 对象包含一个非空的值,返回该值,否则抛出由给定的异常供应者操作生成的异常。
// 使用 orElseThrow(Supplier<? extends X> exceptionSupplier)
Optional<String> name = Optional.ofNullable(null);
String greeting = "Hello, " + name.orElseThrow(() -> new NullPointerException("null"));
// 抛出 java.lang.NullPointerException: null 异常
  • map(Function<? super T,? extends U> mapper):如果 Optional 对象包含一个非空的值,对该值应用给定的映射函数,返回一个包含映射结果的 Optional 对象,否则返回一个空的 Optional 对象。
// 使用 map(Function<? super T,? extends U> mapper)
Optional<String> name = Optional.ofNullable("tom");
String greeting = "Hello, " + name.map(s -> s.toUpperCase()).get();
System.out.println(greeting);
// 输出:Hello TOM
  • flatMap(Function<? super T,Optional<U>> mapper):如果 Optional 对象包含一个非空的值,对该值进行 mapper 参数操作,返回新的 Optional 对象,否则返回一个空的 Optional 对象。
// 使用 flatMap(Function<? super T,Optional<U>> mapper)
Optional<String> name = Optional.ofNullable("tom");
String greeting = name.flatMap(s -> Optional.of("Hello " + s)).get();
System.out.println(greeting);
// 输出:Hello tom
  • filter(Predicate<? super T> predicate):如果 Optional 对象包含一个非空的值,并且该值满足给定的谓词条件,返回包含该值的 Optional 对象,否则返回一个空的 Optional 对象。
// filter(Predicate<? super T> predicate)
Optional<String> name = Optional.ofNullable("tom");
String greeting = "Hello " + name.filter(s -> !s.isEmpty()).get();
System.out.println(greeting);
// 输出:Hello tom

Java 9 中 Optional 改进

Java 9 中 Optional 类有了一些改进,主要是增加了三个新的方法,分别是 stream()、ifPresentOrElse() 和 or()。这些方法可以让我们更方便地处理可能为空的值,以及和流或其他返回 Optional 的方法结合使用。我来详细讲解一下这些方法的作用和用法。

  • stream():这个方法可以将一个 Optional 对象转换为一个 Stream 对象,如果 Optional 对象包含一个非空的值,那么返回的 Stream 对象就包含这个值,否则返回一个空的 Stream 对象。这样我们就可以利用 Stream 的各种操作来处理 Optional 的值,而不需要显式地判断是否为空。我们可以用 stream() 方法来过滤一个包含 Optional 的列表,只保留非空的值,如下所示:
List<Optional<String>> list = Arrays.asList(
        Optional.empty(),
        Optional.of("A"),
        Optional.empty(),
        Optional.of("B")
);

// 使用 stream() 方法过滤列表,只保留非空的值
List<String> filteredList = list.stream()
        .flatMap(Optional::stream)
        .collect(Collectors.toList());

System.out.println(filteredList);
// 输出 [A, B]
  • ifPresentOrElse():这个方法可以让我们在 Optional 对象包含值或者为空时,执行不同的操作。它接受两个参数,一个是 Consumer 类型的 action,一个是 Runnable 类型的 emptyAction。如果 Optional 对象包含一个非空的值,那么就执行 action.accept(value),如果 Optional 对象为空,那么就执行 emptyAction.run()。这样我们就可以避免使用 if-else 语句来判断 Optional 是否为空,而是使用函数式编程的方式来处理不同的情况。我们可以用 ifPresentOrElse() 方法来打印 Optional 的值,或者提示不可用,如下所示 :
Optional<Integer> optional = Optional.of(1);
optional.ifPresentOrElse(
    x -> System.out.println("Value: " + x),
    () -> System.out.println("Not Present.")
);

optional = Optional.empty();
optional.ifPresentOrElse(
    x -> System.out.println("Value: " + x),
    () -> System.out.println("Not Present.")
);

// 输出:Value: 1
// 输出:Not Present.
  • or():这个方法可以让我们在 Optional 对象为空时,返回一个预设的值。它接受一个 Supplier 类型的 supplier,如果 Optional 对象包含一个非空的值,那么就返回这个 Optional 对象本身,如果 Optional 对象为空,那么就返回 supplier.get() 返回的 Optional 对象。这样我们就可以避免使用三元运算符或者其他方式来设置默认值,而是使用函数式编程的方式来提供备选值。我们可以用 or() 方法来设置 Optional 的默认值,如下所示:
Optional<String> optional = Optional.of("Hello ");
Supplier<Optional<String>> supplier = () -> Optional.of("tom");
optional = optional.or(supplier);
optional.ifPresent(x -> System.out.println(x));

optional = Optional.empty();
optional = optional.or(supplier);
optional.ifPresent(x -> System.out.println(x));

// 输出:Hello
// 输出:tom

最后

总结一下使用 Optional 类的几个好处:

  1. 可以避免空指针异常,提高代码的健壮性和可读性。
  2. 可以减少显式的空值检查和 null 的使用,使代码更简洁和优雅。
  3. 可以利用函数式编程的特性,实现更灵活和高效的逻辑处理。
  4. 可以提高代码的可测试性,方便进行单元测试和集成测试。

总之,Optional 类是一个非常有用的类,它可以帮助我们更好地处理可能为空的值,提高代码的质量和效率。所以我强烈推荐你在 Java 开发中使用 Optional 类,你会发现它的魅力和好处。


欢迎加入我的知识星球,全面提升技术能力。

👉 加入方式,长按”或“扫描”下方二维码噢

星球的内容包括:项目实战、面试招聘、源码解析、学习路线。

文章有帮助的话,在看,转发吧。

谢谢支持哟 (*^__^*)

微信扫码关注该文公众号作者

来源:芋道源码

相关新闻

华男开了家“假餐馆”!用3块钱的面做“高档食材” 食客竟排队4小时仅用 30 分钟!开发者做“山寨版” VSCode 扩展,攻破 4830 亿美元巨头,甚至登上了官方热趋榜?突发!新冠超强变种卷土重来,疫苗“不管用了”!澳洲恐面临“寒冬”!这一传染病患者暴增6倍!火出圈的“小京卡”!龙年压岁钱可以当“三笔钱”用了!拜托!别再滥用 ! = null 判空了!!让孩子们爱上读科普,我只用了一个“小心机”!加拿大这省官宣重磅禁令!9月起这些场所全不能用手机!“看不见就不想用了”!社交媒体全禁刚刚安省官宣重磅禁令!9月起这些场所全不能用手机!“看不见就不想用了”!社交媒体全禁别在“臭水沟”里洗衣服了!用它,排出老污垢,杀菌除螨率99%,洗衣机跟新的一样坏事做尽!绿营用零食“自助”吸引民众包围立法机构,手段卑劣今年第一:她用“狼来了”,赢了霉霉!我的“谷歌地图”,终于能用了!5小时赶出来的论文拿Distinction!我发现了比“代写”还好用10倍的写作神器突然爆雷!百果园预计利润暴跌,股价年内跌超70%!杨幂也带不动?网友:月薪两万吃不起!曾被曝“用烂水果做果切”“卖隔夜果切”不挑身材的纯棉T恤也太耐磨耐穿了吧,再也不用“季抛”衣服啦!男女老少都能穿!“My photo”不是“我自己的照片”!你用错了这么久……出门少做这一步,当心变“煤球”!早上用它,一整个夏天都晒不黑,水润不油腻,白到发光~上海“死亡咖啡馆”火了!咖啡只送不卖,用故事来换……过分了!华人无证客被拖欠工资!华人老板吐苦水说:「再也不用华工」!“用脚投票!”加拿大家庭医生没人做,大批人跑去做专科!“别肝论文了!用好AI,20分钟就能完成!”与同行聊天记录曝光后,网友都看傻了!法拉盛华男“耍小聪明”!用无人机往返美加边境送货 最高或判20年餐馆老板叫嚣:“你告我也没用!”时薪$10请杂工…这回惨了!洗洁精都省了!堪称抹布界的“扛把子”!一用就爱上!
logo
联系我们隐私协议©2024 bendi.news
Bendi新闻
Bendi.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Bendi.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。