1. 问题引入

之前写过一篇文章 利用JSR303来完成对象参数校验,我们可以很好的对对象进行参数校验。采用这种方法,我们可以对某个对象被使用之前进行必要的参数校验,如果出现异常,我们可以跑出异常也可以返回结果。但是如果我们想对一个方法的参数进行一些类似非空校验的操作,可否有更好的方法来避免产生java.lang.NullPointerException异常呢?

2. 采用Objects类提供的方法

Objects类是JDK 1.7之后引入的一个Object 工具类,该类主要提个了操作对象的常见的一些方法,例如:

  • public static boolean equals(Object a, Object b): 用于比较两个对象是否相等
  • public static boolean deepEquals(Object a, Object b):也是用于比较两个对象的,如果是数组的话,将对数组中的每个元素都进行比较
  • public static <T> int compare(T a, T b, Comparator<? super T> c):用于两个元素比较的
  • public static <T> T requireNonNull(T obj):检测元素是否为null,如果为null,将抛出NullPointerException,否则返回该对象
  • public static <T> T requireNonNull(T obj, String message):同样的是检查元素是否为null,如果为null的话,抛出的异常带有message
  • public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier):也是检查返回值是否为null,如果是的话,将取messageSupplier的中的信息
  • public static boolean isNull(Object obj):判断元素是否为null,返回boolean值
  • public static boolean nonNull(Object obj):判断元素是否不为null,返回boolean值

其他的还有生成hashCode的一些方法。

下面我们采用其中的requireNonNull来进行检测

public String testObjects(Object arg){
    Object checked= Objects.requireNonNull(arg);
    return checked.toString();
}

如果arg为null将会抛出异常

3. 采用Guava提供的Preconditions

Guava提供的Preconditions中不仅可以对null校验,还有丰富的其他校验方法,我们可以根据Status,State,Index来进行校验

public String testGuava(Object arg){
    Object checked= Preconditions.checkNotNull(arg,"%s must not be null",arg);
   return checked.toString();
}

如果arg为null的话,将输出以下代码:

Exception in thread "main" java.lang.NullPointerException: arg is marked non-null but is null
	at com.liuyao.check.TestNonNull.testLombok(TestNonNull.java:23)
	at com.liuyao.check.TestNonNull.main(TestNonNull.java:31)

4. 采用Lombok中的@NonNull注解

Lombok也提供了一个@NonNull注解在方法的声明中进行校验,例如下面的代码

public String testLombok(@NonNull Object arg){
   return arg.toString();
}

Lombok会生成如下代码:

public void testLombok(Object arg) {
  if (arg == null) {
    throw new NullPointerException("arg is marked @NonNull but is null");
  }
  arg.toString();
}

5. 采用Checker Framework 中提供的@Nullable和@NonNull

Checker Framework 能够作为 javac 编译器的插件运行,对代码中的数据类型进行检测,预防各类问题。我们可以参照 官方文档,将 Checker Framework 与 maven-compiler-plugin 结合,之后每次执行 mvn compile 时就会进行检查。Checker Framework 的空值检测程序支持几乎所有的注解,包括 JSR 305、Eclipse、甚至 lombok.NonNull

例如:

import org.checkerframework.checker.nullness.qual.Nullable;

@Nullable
private Object returnNullable() {
  return null;
}

public void testReturnNullable() {
  Object obj = returnNullable();
  // 错误:obj 可能为空
  System.out.println(obj.toString());
}

6. 参考链接

  1. Lombok features
  2. Java java.util.Objects类
  3. Java Objects类
  4. The Checker Framework
  5. Java 8 Annotation 新特性在软件质量和开发效率方面的提升