Java 是如何优雅地处理NPE问题的

1. 前言

对于 Java 开发者来讲,null 是一个使人头疼的类型,一不当心就会发生 NPE (空指针) 问题。也是 Java 语言为人诟病的一个重要缘由之一。在咱们消除可恶的 NPE 问题以前咱们要回顾一下 Java 中 null 的概念。html

2. Java 中的 null

翻译自 Oracle Java 文档java

Java语言中有两种类型,一种是 基本类型 ,另外一种是 引用类型。还有一种没有名字的特殊类型,即表达式 null
因为 null 类型没有名称,因此不可能声明为 null 类型的变量或者转换为 null 类型。
null 引用是 null 类型表达式惟一可能的值。
null 引用能够转换为任意引用类型。
事实上,程序员能够忽略 null类型,能够认为 null仅仅是一个能够成为任何引用类型的特殊符号。

从上面的描述咱们能够了解到,其实 null 仅仅是一个关键字标识量,既不是一种类型也不算对象,没法直接声明 null 和被转换为 null,仅仅只能被引用,null 能够转换为任何引用类型。当一个 Java 引用类型对象被引用为 null 时表明当前对象不引用对象,并无为其分配内存。 这也是咱们在没有引用的对象上调用方法出现空指针的根本缘由。
大多数状况下 Java 开发者使用 null 是为了表示某种不存在的意思。程序员

3. NPE 问题的解决

不少时候咱们对数据是否存在有本身的指望,可是这种指望并不能直接被咱们掌控,一个返回值为 null 所表达的意思并不明确过于模糊,每每经过是否判断为 null 来规避空指针问题。因而 Google 工程师在他们的 Guava 工具类库中设计了 Optional<T> 来解决 null 不可控的问题。 让你在不得不使用 null 的时候,能够更加简便明确的使用 null 并帮助你避免直接使用 null 带来的问题。
Java 8 将此设计吸取。咱们能够直接使用 Java 提供的 Optional 来解决空指针问题。接下来咱们来研究一下 Java 8 中的 Optional编程

4. Java 8 中的 Optional

Java 8 中的 Optional 是一个可选值的包装类。它的意义不只仅帮咱们简化了 NPE 问题的处理,同时也是 Java 函数式编程的一个重要辅助。 咱们接下来将对其 API 进行讲解以帮助你在实际开发中使用他们。安全

4.1 Optional 声明

Optional 只能经过静态方法来声明。它提供了三个静态方法:oracle

empty() 返回一个值为 nullOptional 实例函数式编程

Optional<Object> empty = Optional.empty();

of(T) 返回一个值不为 nullOptional 实例函数

Optional<String> nonNull = Optional.of("Felordcn");

ofNullable() 返回一个值可能为 nullOptional 实例工具

// value 值来自其它不肯定的来源
 String value = SomeApi.source();
 // 可能为 null 
 Optional<String> nullable = Optional.ofNullable(value);
 // 也可能不为 null 
 Optional<String>  hasValue = Optional.ofNullable(value);

4.2 其它方法

isPresent() 若是值存在则返回 true,不然返回 false 。若是 Optional 值不肯定,可以使用该方法进行安全校验spa

Optional<String> nonNull = Optional.of("Felordcn");
  // true      
  boolean present =nonNull.isPresent();

get() 获取 Optional 中的值,若是为空会抛出 NoSuchElementException 异常

Optional<String> nonNull = Optional.of("Felordcn");
  // Felordcn      
  String str = nonNull.get();

ifPresent(Consumer) 若是值存在则该值被消费函数 Consumer 消费 , 不然不作任何事情。 isPresent() 增强版

//  非空打印出字符串     
      nullable.ifPresent(System.out::println);
     
     //等同于
      if (nullable.isPresent()) {
                 System.out.println(nonNull);
      }

filter(Predicate) 若是值知足断言函数 Predicate 则返回该 Optional,不然返回 Optional.empty()

Optional<String> nonNull = Optional.of("Felordcn");
 Optional<String> felord = nonNull.filter(s -> s.startsWith("Felord"));
 // str = "Felordcn"
 String str = felord.get();

map(Function) 获取元素某个属性的 Optional 。 若是该属性为 null 返回 Optional.empty() ,不然返回对应值的 Optional

Optional<User> userOpt = Optional.ofNullable(user);
//  username 为空 则为 空  Optional  
 Optional<String> usernameOpt = userOpt.map(User::getUsername);

flatMap(Function) 有时候咱们会返回 Optional<Optional<T>> 很是不便于处理,咱们须要将元素展开,可以使用该方法处理,参考 Stream Api 中的相关方法

orElse(other) 若是 Optional 的值存在,返回 Optional, 不然指定一个 Optional

orElseGet(Supplier) 若是 Optional 的值存在,返回 Optional, 不然指定一个执行 Supplier 函数来获取值

orElseThrow(Supplier<? extends Throwable>) 若是 Optional 的值存在,返回 Optional, 不然抛出一个指定 Supplier 函数提供的异常

4.3 Java 9 中的新API

or(Supplier) orElseGet 的改进类型。不仅仅返回具体的值,而能够函数式的返回 Optional

stream()OptionalStream 打通

ifPresentOrElse(Consumer) ifPresent 方法提供了有值后的消费逻辑而没有值的逻辑没有提供入口。新方法 ifPresentOrElse 弥补了这一缺陷

5. Optional 的使用误区

Optional 很香可是也不能滥用。一个危险的举动就是将 Optional 做为入参传递给方法。 由于入参是不可控的,你没法保证入参中的 Optional 是否为 null。这偏偏违背了 Optional 的本意。因此尽可能在表达式中使用 Optional 或者在返回值中使用,而不是在方法的参数中使用 Optional

6. 总结

今天对 Optional 进行讲解。从 Optional 的设计本意到其经常使用的方法。咱们也对 OptionalJava 9 中的新 API 进行了介绍。另外 Optional 也不是万能的,合理的使用才能发挥其优点。但愿今天的文章对你有用。

关注公众号:Felordcn 获取更多资讯

我的博客:https://felord.cn

相关文章
相关标签/搜索