public void doSomething() {
String result = doSomethingElse();
if (result.equalsIgnoreCase("Success"))
// success
}
}
private String doSomethingElse() {
return null;
}
在这里,我们尝试调用null引用的方法调用。这将导致NullPointerException。public static void main(String[] args) {
findMax(null);
}
private static void findMax(int[] arr) {
int max = arr[0];
}
这会在第6行导致 NullPointerException。public void doSomething() {
String result = doSomethingElse();
if (result != null && result.equalsIgnoreCase("Success")) {
// success
}
else
// failure
}
private String doSomethingElse() {
return null;
}
在实际中,程序员发现很难识别哪些对象可以为 null。 积极安全的策略可能是为每个对象检查 null。但是,这会导致大量冗余空值 检查,并使我们的代码可读性降低。public void print(Object param) {
System.out.println("Printing " + param);
}
public Object process() throws Exception {
Object result = doSomething();
if (result == null) {
throw new Exception("Processing fail. Got a null response");
} else {
return result;
}
}
在print()方法调用将只打印“空”,但不会抛出异常。同样, process() 永远不会在其响应中返回 null 。它反而抛出异常。public void accept(@Nonnull Object param) {
System.out.println(param.toString());
}
在这里, @ NonNull 清楚地表明参数不能为 null。 如果客户端代码在不检查null参数的情况下调用此方法 ,则 FindBugs将在编译时生成警告。
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>16.0.2</version>
</dependency>
现在,如果缺少空 检查,IntelliJ将生成警告,就像我们在上一个示例中一样。public void accept(Object param){
assert param != null;
doSomething(param);
}
在第2行中,我们检查null参数。如果启用了断言,则会导致 AssertionError。public void goodAccept(String one, String two, String three) {
if (one == null || two == null || three == null) {
throw new IllegalArgumentException();
}
process(one);
process(two);
process(three);
}
public void badAccept(String one, String two, String three) {
if (one == null) {
throw new IllegalArgumentException();
} else {
process(one);
}
if (two == null) {
throw new IllegalArgumentException();
} else {
process(two);
}
if (three == null) {
throw new IllegalArgumentException();
} else {
process(three);
}
}
显然,我们应该更喜欢goodAccept()而不是badAccept()。public static int primitiveSum(int a, int b) {
return a + b;
}
public static Integer wrapperSum(Integer a, Integer b) {
return a + b;
}
现在,让我们在客户端代码中调用这些API:
int sum = primitiveSum(null, 2);
这将导致编译时错误,因为 null 不是int的有效值 。assertThrows(NullPointerException.class, () -> wrapperSum(null, 2));
还有其他因素可以使用原语而不是包装器public List<String> names() {
if (userExists()) {
return Stream.of(readName()).collect(Collectors.toList());
} else {
return Collections.emptyList();
}
}
因此,我们在调用此方法时避免了客户端执行空检查的需要。
public void accept(Object param) {
Objects.requireNonNull(param);
// doSomething()
}
现在,让我们测试accept() 方法:
assertThrows(NullPointerException.class, () -> accept(null));
因此,如果将null 作为参数传递,则 accept()会抛出NullPointerException。Java 8 在该语言中引入了一个新的Optional API。与null相比,这为处理可选值提供了更好的合约。 让我们看看Optional 如何消除对空 检查的需要 :
public Optional<Object> process(boolean processed) {
String response = doSomething(processed);
if (response == null) {
return Optional.empty();
}
return Optional.of(response);
}
private String doSomething(boolean processed) {
if (processed) {
return "passed";
} else {
return null;
}
}
通过返回一个 可选选项, 如上图所示,该 处理()方法使得明确给调用者,响应可以是空的,并且必须在编译时被处理。assertThrows(Exception.class, () -> process(false).orElseThrow(() -> new Exception()));
此外,它还为API开发人员提供了一个更好的合同,以向客户表明API可以返回空响应。public Optional<Object> process(boolean processed) {
String response = doSomething(processed);
return Optional.ofNullable(response);
}
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
现在,我们可以在需要进行空 检查的地方 使用@NonNull :
public void accept(@NonNull Object param){
System.out.println(param);
}
因此,我们只是注释了需要进行null 检查的对象,并且Lombok生成了已编译的类:
public void accept(@NonNull Object param) {
if (param == null) {
throw new NullPointerException("param");
} else {
System.out.println(param);
}
}
如果 param 为null,则此方法抛出NullPointerException。 该方法必须在其合同中明确说明,并且客户端代码必须处理异常。
public void accept(String param){
if (null != param && !param.isEmpty())
System.out.println(param);
}
如果我们必须处理很多String 类型,这很快就会变得多余。这是 StringUtils 派上用场的地方。在我们看到这个动作之前,让我们为commons-lang3添加一个Maven依赖项:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
现在让我们用StringUtils重构上面的代码 :
public void accept(String param) {
if (StringUtils.isNotEmpty(param))
System.out.println(param);
}
因此,我们使用静态 实用程序方法 isNotEmpty()替换了 null 或空检查 。 此API提供了其他强大的实用方法来处理常见的 String函数。http://blog.xqlee.com/article/563.html