Okay, I\'ve got a question about handling nulls. This question can be heavily based upon opinion, therefore I\'m going to ask about pro\'s and cons.
Let\'s say I\'ve got
Have you taken a look at Java 8's Optional
class? This is an object wrapper that lets you handle null in a functional way.
For example, if you have a method public JSONArray getArray()
that you want to always return something other than null, you can use your code. Using Optional, it would change to this:
public Optional<JSONArray> getArray() {
// jsonArray comes from somewhere
return Optional.ofNullable(jsonArray);
}
In cases where jsonArray is null, the optional will be empty; in cases where it's not null, it will contain jsonArray.
You can then replace null checks with behaviour dictated by the optional. Instead of
JSONArray array = getArray();
if (array != null) {
// do something
}
you replace it with
getArray().ifPresent(array -> // do something);
This means you don't need to create empty JSONArrays, or Lists, or Sets, or Strings, or whatever. In cases where the wrapped object is actually null, a singleton Optional is returned from Optional.ofNullable
, further reducing overhead.
If you still want to take a classic approach, that's possible too. Since if (option == null)
should always evaluate to false
(if you return null instead of an Optional, you kind of miss the point!), you woud use if (option.isPresent())
.
If you're not using Java 8, you can either write your own Optional or use a third-party library such as Guava.
EDIT: Non-Java 8 solutions
Use something like Guava - take a look at http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Optional.html
Write your own! In this implementation, Supplier
, Consumer
and Predicate
are interfaces that return, accept or test an object.
public abstract class Option<T> implements Iterable<T> {
private static final Option NONE = new None();
private Option() {
// no-op
}
public static <T> Option<T> of(T t) {
return t == null ? NONE : new Some<T>(t);
}
public static <T> Option<T> empty() {
return NONE;
}
public abstract T get();
public abstract T orElse(T fallback);
public abstract T orElse(Supplier<T> supplier);
public abstract <E extends Exception> T orThrow(Supplier<E> exceptionSupplier) throws E;
public abstract boolean isPresent();
public abstract Option<T> filter(Predicate<T> predicate);
public abstract void ifPresent(Consumer<T> consumer);
public abstract <O> Option<O> ifPresent(Function<T, O> function);
private static final class Some<T> extends Option<T> {
private final T value;
private Some(final T value) {
this.value = value;
}
@Override
public T get() {
return value;
}
@Override
public T orElse(final T fallback) {
return value;
}
@Override
public T orElse(final Supplier<T> supplier) {
return value;
}
@Override
public <E extends Exception> T orThrow(final Supplier<E> exceptionSupplier) throws E {
return value;
}
@Override
public boolean isPresent() {
return true;
}
@Override
public Option<T> filter(final Predicate<T> predicate) {
return predicate.test(value) ? this
: NONE;
}
@Override
public void ifPresent(final Consumer<T> consumer) {
consumer.consume(value);
}
@Override
public <O> Option<O> ifPresent(final Function<T, O> function) {
return Option.of(function.apply(value));
}
@Override
public Iterator<T> iterator() {
return Collections.singletonList(value).iterator();
}
}
private static final class None<T> extends Option<T> {
@Override
public T get() {
throw new IllegalStateException("value not defined");
}
@Override
public T orElse(final T fallback) {
return fallback;
}
@Override
public T orElse(final Supplier<T> supplier) {
return supplier.get();
}
@Override
public <E extends Exception> T orThrow(final Supplier<E> exceptionSupplier) throws E {
throw exceptionSupplier.get();
}
@Override
public boolean isPresent() {
return false;
}
@Override
public Option<T> filter(final Predicate<T> predicate) {
return this;
}
@Override
public void ifPresent(final Consumer<T> consumer) {
// no-op
}
@Override
public <O> Option<O> ifPresent(final Function<T, O> function) {
return NONE;
}
@Override
public Iterator<T> iterator() {
return Collections.<T>emptyList().iterator();
}
}
}