2

I've been reading articles on beeing null safe in java, and how it's bad to return null, or of that sin, that is passing null as an argument. I get that it simplifies life, and people don't always read documentation, so they don't know wheather a method can return null, or if null can be passed to it. Annotations seem to just pollute the code, and there is no Kotlin-like null safety mechanism. In my current project I try to design everything in such a manner, that null is almost unnecessary, at least for the end-user.

I want to create a change listener (something like javafx.beans.value.ChangeListener), such that i can pass a previous and a current value to the changed() method. The thing is, I want it to be null safe, so I don't want to ever pass a null as an argument, even though it can change from no value to some value, or from some value to no value. I could add two additional methods for that situation and have something like:

public inteface ChangeListener<T> {
    void valueSet(T current);
    void valueChanged(T previous, T current);
    void valueCleared(T previous);
}

This approach seems excessive though. I could also use java.util.Optional<T> as arguments, but that adds additional boxing:

public inteface ChangeListener<T> {
    void changed(Optional<T> previous, Optional<T> current);
}

Is there a more elegant option? Or should I force user to use some sort of a Null Object Pattern? Although that will create problems with the need to extend some classes. I could also stop caring, specify in the documentation what will happen if null is used, and let the user find the source of all the NullPointerExceptions.

clay_golem
  • 37
  • 1
  • 4
  • It seems that you have covered pretty much all the usual options. – assylias Jan 12 '18 at 15:07
  • `void changed(Optional previous, Optional current);` - this does not really give you any benefit. To be really `null`-safe, you would have to check whether the parameters themself were `null`. – Turing85 Jan 12 '18 at 15:09
  • You can put the `@Nullable` annotation on `previous` parameter to show that it can be `null`. – Florent Bayle Jan 12 '18 at 15:10
  • @Turing85 Not sure why you insist on checking Optional for null - a null Optional is a design error (i.e. a bug). – assylias Jan 12 '18 at 15:16
  • @assylias well you either want to be `null`-safe or not. If OP checks for a documented not-`null`, it would only be consistent to check whether the passed `Optional` is not-`null` as well. – Turing85 Jan 12 '18 at 15:18
  • @Turing85 One could pass `null` instead of an `Optional`, but that would be caused by user's design (if one decided to use my interface). On my side I could assure, that it will always, empty or not, be an `Optional` object. – clay_golem Jan 12 '18 at 15:18
  • @assylias just to make my point clear, here is a cite from Brian Goetz on the topic: ["*You should almost never use it as a field of something or a method parameter.*"](https://stackoverflow.com/a/26328555/4216641) – Turing85 Jan 12 '18 at 15:28
  • What's the problem with passing nulls? If the previous/new value is a null, then you should pass a null because that is the actual value. Passing anything else would not accurately represent the transition. – Bohemian Jan 12 '18 at 15:40
  • @Turing85 Agreed, in this case `Optional` usage is like burning a house just to get rid of a mouse - an overkill. Additional methods introduce unnecessary complexity. I think, I'll just, as [SeverityOne](https://stackoverflow.com/questions/48228808/i-need-an-advice-on-null-safety-in-java/48229102#48229102) said, document the behaviour. Maybe I will get more comfortable with `@Nullable` and `@Nonnull` – clay_golem Jan 12 '18 at 15:52
  • @Maniek there is still the option of [`Objects.requireNonNull(...)`](https://docs.oracle.com/javase/8/docs/api/java/util/Objects.html#requireNonNull-T-)... – Turing85 Jan 12 '18 at 15:56
  • @Turing85 I'm using [Guava's Preconditions](https://github.com/google/guava/wiki/PreconditionsExplained) for null and argument checking, but it's not that I wanted to check that. I wanted to make sure, that the user won't have to. – clay_golem Jan 12 '18 at 16:01

1 Answers1

4

Be a bit careful when people tell you "XYZ considered harmful". I've seen people do away with constructors altogether in favour of factory methods (such as Optional.of(...)), but as with everything, there's no single correct answer.

You seem to be struggling with trying to achieve several things (using simple code, having only one method in the listener, not using null values) that are mutually exclusive. So stop worrying and focus on what's important.

If your API users are idiots, and they don't read documentation, that's not really your problem. Null is not something dirty; it means "undefined". What is dubious is to use null if something unexpected happened, like "file not found", which should ideally be dealt with via an exception.

If "undefined" is a correct representation of an unset value in your API, then there's nothing wrong with using null.

SeverityOne
  • 2,476
  • 12
  • 25
  • I completely agree. `null` is a very good representation for an unset value, as it will immediately throw an exception whenever someone tries to call any method on it, making sure it can't be confused for some valid value. – Ralf Kleberhoff Jan 12 '18 at 16:40