关于null

java.lang.NullPointerException 不幸中的万幸?

NullPointerException应该是最常遇见的异常,但通常也比较容易解决
好的编程习惯可以减少这类异常的发生

返回值


函数的返回值尽量不要设计成返回null, 设计成null势必需要调用者进行检查,阻碍链式调用
如果没有特殊原因,可以返回空值代替null

  • 字符串类型:Commons-lang的StringUtils可以返回空字符串StringUtils.EMPTY
  • 数组类型:Commons-lang的ArrayUtils可以返回一系列空数组如ArrayUtils.EMPTY_INT_ARRAY
  • 集合类型:Java自带的Collections可以返回空集合,并且都是不可变的,如Collections.emptyMap(),Collections.emptySet(),Collections.emptyList()
    如果方法一定要返回null,应该详细注释

Optional


Java8引入了Optional类,标准库引入之前,Guava类库也提供类似功能
如果一定需要表示没有的情况,可以使用Optional
Optional是null的包装类,实现上仅仅是包含一个泛型变量
Optional顾名思义就是可选值,也就是表示可能有null存在。语义上更加明确,避免了以往忘记检查null的情况

Optional.java
1
2
3
4
public final class Optional<T>{
private final T value;
//...
}

包含四种基本操作:

  • of/ofNullable 值包装成Optional
  • isPresent 判断是否有值
  • get 从Optional取出值
  • orElse 无值时返回指定值

还有和lambda结合的操作

  • ifPresent 有值时执行操作
  • orElseGet 无值时执行操作生成指定值
  • map/flatMap 转换生成新Optional或空Optional
  • filter 条件返回自身或空Optional

Option在使用时,遇到null值就用空对象表示,相当于在内部消除了null

Optional.java
1
2
3
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}

lambda操作的返回值也都是Optional,可以解决链式调用问题

Optional.java
1
2
3
4
5
6
7
8
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}

比如obj.getA().getB().getC(),中间A和B都可能是null,影响调用链,需要检查

1
2
3
if(obj.getA() != null && obj.getA().getB() != null) {
obj.getA().getB().getC();
}

使用Optional可以

1
2
3
4
5
Optional.ofNullable(obj)
.map(o->o.getA())
.map(o->o.getB())
.map(o->o.getC())
.orElse(null);

equals比较


因为对等性a.equals(b)和b.equals(a)效果是一样的,但是已知量在前可以避免NullPointer。

1
2
"abc".equals(str); //str为null,返回false
str.equals("abc"); //str为null,报NullPointer异常

Java7 Objects.equals
内部处理null逻辑,使用时可以无视顺序

Objects.java
1
2
3
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}

toString


尽量不用str.toString(),可以使用String.valueOf(str)
可以看出valueOf方法也是最终调用toString(),但好处是包含了null值检查

String.java
1
2
3
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}

Java7 Objects.toString
toString名字比较直观,为了继续使用,再包装一层

Objects.java
1
2
3
public static String toString(Object o) {
return String.valueOf(o);
}

还可以在null值时使用替代值

Objects.java
1
2
3
public static String toString(Object o, String nullDefault) {
return (o != null) ? o.toString() : nullDefault;
}

null防卫


检查到是null就抛出NullPointerException
Java7 Objects.requireNotNULL

Objects.java
1
2
3
4
5
public static <T> T requireNonNull(T obj, String message) {
if (obj == null)
throw new NullPointerException(message);
return obj;
}

null判断


如果厌倦了obj == null这种判断,还可以采用Objects类在Java8中提供的方法

Objects.java
1
2
3
4
5
6
public static boolean isNull(Object obj) {
return obj == null;
}
public static boolean nonNull(Object obj) {
return obj != null;
}

多值情况下可以用commons.lang3ObjectUtils.allNotNullObjectUtils.anyNotNull

空判断


拿到一个可能空值的对象,首先要null判定然后才能空值判定
可以使用null容忍的工具类

  • 针对String类型,可以采用commons.lang中的StringUtils.isEmpty
  • 针对数组类型,可以采用commons.lang中的ArrayUtils.isEmpty
  • 针对集合类型, 可以采用commons.collections中的Collections.isEmpty

null替换默认值


commons.lang3ObjectUtils.defaultIfNull
典型的情况是数字拆箱

1
2
Integer objValue = null;
int rawValue = ObjectUtils.defaultIfNull(objValue,0);