没有人喜欢空指针异常 ! 我们有办法摆脱它们吗?
也许 。 。 。
这篇文章中讨论了几种技术:
- 可选类型(Java 8中的新增功能)
- 对象类(旧的Java 7东西!)
Java 8中的可选类型
它是什么?
- Java 8中引入的一种新类型(类)
- 打算充当特定类型的对象或没有对象(空)的方案的“ 包装器 ”
用简单的话来说,它是处理空值的更好替代品 ( 警告 :起初可能不是很明显!)
基本用法
它是一种类型(一个类)–那么,如何创建它的实例?
只需在Optional类中使用三个静态方法。
public static Optional<String> stringOptional(String input) {
return Optional.of(input);
}
简单明了–创建一个包含值的Optional包装器。 当心–如果值本身为null,将抛出NPE!
public static Optional<String> stringNullableOptional(String input) {
if (!new Random().nextBoolean()) {
input = null;
}
return Optional.ofNullable(input);
}
我个人认为好一点。 这里没有NPE的风险–如果输入为空,则将返回空的 Optional。
public static Optional<String> emptyOptional() {
return Optional.empty();
}
如果您要有目的地返回“空”值。 'empty'并不意味着null 。
好了–使用/使用Optional怎么样?
public static void consumingOptional() {
Optional<String> wrapped = Optional.of("aString");
if (wrapped.isPresent()) {
System.out.println("Got string - " + wrapped.get());
}
else {
System.out.println("Gotcha !");
}
}
一种简单的方法是检查Optional包装器是否具有实际值(使用isPresent方法)–这将使您想知道它是否比使用if(myObj!= null)好 。 不用担心,我也会解释这一点。
public static void consumingNullableOptional() {
String input = null;
if (new Random().nextBoolean()) {
input = "iCanBeNull";
}
Optional<String> wrapped = Optional.ofNullable(input);
System.out.println(wrapped.orElse("default"));
}
如果包装的值为null,则可以使用orElse来返回默认值,这是显而易见的。 我们避免了在提取实际值之前调用ifPresent的明显冗长。
public static void consumingEmptyOptional() {
String input = null;
if (new Random().nextBoolean()) {
input = "iCanBeNull";
}
Optional<String> wrapped = Optional.ofNullable(input);
System.out.println(wrapped.orElseGet(
() -> {
return "defaultBySupplier";
}
));
}
我对此有些困惑。 为什么要使用两种单独的方法来实现相似的目标? orElse和orElseGet很可能已被重载 (相同名称,不同参数)。
无论如何,这里唯一明显的区别是参数本身–您可以选择提供一个Lambda表达式来表示Supplier <T> (功能接口)的实例。
与常规的空值检查相比,使用Optional更好吗?
- 总的来说,使用Optional的主要好处是能够清楚地表达您的意图 -简单地从方法中返回null会使消费者在怀疑是否故意的时候(当实际的NPE出现时)充满了疑惑。并且需要对Javadocs进行进一步的内省(如果有)。 借助Optional,其水晶般清晰 !
- 有以下几种方式可以完全避免NPE与可选-在上面的例子中所提到的,使用Optional.ofNullable(可选创建过程中)和否则容易和orElseGet(可选消费过程中)从NPE上保护我们一起
另一个救星!
(以防您无法使用Java 8)
查看此代码段。
package com.abhirockzz.wordpress.npesaviors;
import java.util.Map;
import java.util.Objects;
public class UsingObjects {
String getVal(Map<String, String> aMap, String key) {
return aMap.containsKey(key) ? aMap.get(key) : null;
}
public static void main(String[] args) {
UsingObjects obj = new UsingObjects();
obj.getVal(null, "dummy");
}
}
什么可能为空?
- 地图对象
- 执行搜索所依据的密钥
- 在其上调用方法的实例
在这种情况下抛出NPE时,我们永远无法确定什么是null ?
输入对象类
package com.abhirockzz.wordpress.npesaviors;
import java.util.Map;
import java.util.Objects;
public class UsingObjects {
String getValSafe(Map<String, String> aMap, String key) {
Map<String, String> safeMap = Objects.requireNonNull(aMap,
"Map is null");
String safeKey = Objects.requireNonNull(key, "Key is null");
return safeMap.containsKey(safeKey) ? safeMap.get(safeKey) : null;
}
public static void main(String[] args) {
UsingObjects obj = new UsingObjects();
obj.getValSafe(null, "dummy");
}
}
requireNonNull方法:
- 如果它不为空,则简单地返回值
- 如果值为null,则将向NPE投掷指定的消息
为什么这比if(myObj!= null)更好
您将看到的堆栈跟踪将明显具有Objects.requireNonNull方法调用。 这以及您的自定义错误消息将帮助您更快地发现错误。 。 .IMO快得多!
您也可以编写用户定义的检查,例如,实施强制执行非空性的简单检查
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
public class RandomGist {
public static <T> T requireNonEmpty(T object, Predicate<T> predicate, String msgToCaller){
Objects.requireNonNull(object);
Objects.requireNonNull(predicate);
if (predicate.test(object)){
throw new IllegalArgumentException(msgToCaller);
}
return object;
}
public static void main(String[] args) {
//Usage 1: an empty string (intentional)
String s = "";
System.out.println(requireNonEmpty(Objects.requireNonNull(s), (s1) -> s1.isEmpty() , "My String is Empty!"));
//Usage 2: an empty List (intentional)
List list = Collections.emptyList();
System.out.println(requireNonEmpty(Objects.requireNonNull(list), (l) -> l.isEmpty(), "List is Empty!").size());
//Usage 3: an empty User (intentional)
User user = new User("");
System.out.println(requireNonEmpty(Objects.requireNonNull(user), (u) -> u.getName().isEmpty(), "User is Empty!"));
}
private static class User {
private String name;
public User(String name){
this.name = name;
}
public String getName(){
return name;
}
}
}
不要让NPE在错误的地方痛苦。 我们拥有一套不错的工具来更好地处理NPE或完全消除它们!
干杯!
翻译自: https://www.javacodegeeks.com/2014/09/optional-and-objects-null-pointer-saviours.html