没有人喜欢空指针异常 ! 我们有办法摆脱它们吗?
也许 。 。 。
这篇文章中讨论了几种技术:
- 可选类型(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