AlphaWang.com

Alpha's Programming Notes | 一个程序员的日常

Google Guava: 1. Dealing With Null

Please ref to the demo code: git clone https://github.com/AlphaWang/guava-demo.git

Many of Guava’s utilities are designed to fail fast in the presence of null rather than allow nulls to be used.

com.alphawang.guava.ch1.optional.Test1_FailFast

1
2
3
4
5
6
7
8
  // Lists.newArrayList()
  public static <E> ArrayList<E> newArrayList(E... elements) {
    checkNotNull(elements); 
    int capacity = computeArrayListCapacity(elements.length);
    ArrayList<E> list = new ArrayList<E>(capacity);
    Collections.addAll(list, elements);
    return list;
  }

Additionally, Guava provides a number of facilities both to make using null easier, when you must, and to help you avoid using null.

Null object pattern

see http://www.tutorialspoint.com/design_pattern/null_object_pattern.htm

  • Consider if there is a natural “null object” that can be used.

If it’s an enum, add a constant to mean whatever you’re expecting null to mean here.

example 1, java.math.RoundingMode has an UNNECESSARY value to indicate “do no rounding, and throw an exception if rounding would be necessary.”

example 2: use Unit.NONE instead of null.

1
2
3
4
5
6
7
8
9
public enum Unit {
   NONE("없음", "1"),

   // 길이(cm)
   MM("mm", "0.1"),
   CM("cm", "1"),
   M("m", "100"),
   KM("km", "100000"), ...
}
  • Never return null.

For example, return a empty list instead of null.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//BEFORE
public List<String> getNames(Long id) {
  if (id != null) {
      return service.getNames(id);
  }
  return null;
}

//AFTER
public List<String> getNames(Long id) {
  if (id != null) {
      return service.getNames(id);
  }
  return Collections.EMPTY_LIST;
}

Optional

com.alphawang.guava.ch1.optional.Test2_Optional

Optional<T> is a way of replacing a nullable T reference with a non-null value.

Besides the increase in readability that comes from giving null a name, the biggest advantage of Optional is its idiot-proof-ness. It forces you to actively think about the absent case if you want your program to compile at all, since you have to actively unwrap the Optional and address that case.

there are two main use cases of Optional.

  • remind your client that the returned value can be null, can force he to check null case: api:
1
2
3
4
public Optional<Object> api() {
    ...
    return Optional.fromNullable(nullableObj); // return Optional instead of nullableObj
}

client:

1
2
3
Optional<Object> optional = api();
if (optional.isPresent()) { // force null-check
} 
  • return a default value if the object is null:
1
Object obj = Optional.fromNullable(nullableObj).or(defaultObj);

Enums

Enums#getIfPresent can help to get an Optional from a enum value.

1
2
3
4
5
6
7
8
9
10
11
    // BEFORE
    VitaminLocale vitaminLocale = VitaminLocale.valueOf("ko_KR");
    if (vitaminLocale != null) {

    }

    // AFTER
    Optional<VitaminLocale> locale = Enums.getIfPresent(VitaminLocale.class, "ko_KR");
    if (locale.isPresent()) {
        locale.get();
    }

Objects

com.alphawang.guava.ch1.optional.Test3_Objects

MoreObjects.firstNonNull is an alternative of Optional.or, both can return a default value if the object is null.

1
MoreObjects.firstNonNull(cityService.getNullableCity(1L), defaultCity);

Preconditions

com.alphawang.guava.ch1.optional.Test4_Preconditions

Of course we can fail fast in the presence of null, just like guava code. Guava provides Preconditions.checkArgument and Preconditions.checkNotNull to do this.

1
2
3
4
5
6
7
public City save(City city) {
    Preconditions.checkArgument(city != null, "IllegalArgumentException: city is null");
    // or
    city = Preconditions.checkNotNull(city, "NullPointerException: city is null");

    return cityRepository.save(city);
}

Reference

java

« Key Solr Concepts Google Guava: 2. Collections »