I have seen the following pattern appear quite a lot:

private String foo(String bar) {
  if(bar != null){
    return "bar";
  }
  return null;
}

Here the function is called with a nullable argument, and if the argument was null, the function will return null, and if not it will return a proper value. I do not like this, and here is why.

Function signature

If we would use JSR-305 annotations, the function signature would look like this:

@Nullable
private String nullableFoo(@Nullable String bar){
  if(bar != null){
    return "bar";
  }
  return null;
}

And I do not like this signature, because if we wouldn’t have accepted null as an input in the first place the signature would look like this:

@Nonnull
private String nonnullFoo(@Nonnull String bar) {
  return "bar";
}

Meaning that if the input would be null, we would have to deal with it in the following way:

private void bar() {
  String input = null;
  String result = nullableFoo(input);
  String result2 = input != null ? nonnullFoo(input) : null;
}

Which would mean moving the null check outside of the function. However, it also means that if we would have a correct input value the following happens:

private void bar() {
  String input = "a";
  String result = nullableFoo(input); //result is now nullable according to the signature
  String result2 = nonnullFoo(input); //result is now nonnull according to the signature
}

So because of the function signature we can go from a valid state (nonnull) to an invalid state (nullable). Therefore I suggest to move the null check outside of the function, so that the caller is in control of the state. This way, it not only makes the function itself a lot simpler (moving the complexity to where it is needed), it also makes sure a valid state will not go to an invalid state because of the signature.

It becomes even more apparent if we write the signature using Optionals

private Optional<String> optionalFoo(Optional<String> bar) {
  return bar.map( v -> "bar");
}

private void bar() {
  String input = "a";
  String result = optionalFoo(Optional.of(input))
   .map( v -> "a") // do your thing
   .orElse("b") // forced to handle something that can never happen
}

Conclusion

Returning null from a function does a lot of harm to the function signature, and makes the function more complex. By moving the null check outside of the function, only the places that have an invalid state anyway have to deal with it, keeping the rest of your code clean.

shadow-left