8

I know that the best practice for handling null primitives was to use a boxed wrapper, such as Integer instead of int, as discussed here

Null for primitive data types

However, does this still remain true today with Java 8 which introduced optional primitives such as OptionalInt, whose OptionalInt.empty() effectively represents a null value? My understanding is that Optionals should only be used for method return types, not as types for the properties themselves. Should "nullable" primitives still be stored as boxed properties? Should they only be Optional in the method return types? Or be stored as OptionalInt in the property itself?

Community
  • 1
  • 1
tmn
  • 11,121
  • 15
  • 56
  • 112
  • Do you know of advantages of using `OptionalInt` over plain old `Integer`? With the latter, you can just assign it to `null` and handle it accordingly in, seemingly, the same manner you would with `OptionalInt` and `isEmpty()`. This is an interesting question. – Chris Sprague Apr 10 '15 at 05:11
  • 6
    In your application's data model, what are the semantics of a value being "null"? – Stuart Marks Apr 10 '15 at 05:43
  • Okay so what does everyone mean by semantics? Like using 0 or -1 to flag an absent int value? Or what business context the optional is used? – tmn Apr 10 '15 at 11:28
  • *"Okay so what does everyone mean by semantics?"* Semantics (*"meaning of words"*) are what it *means* to have a null `Integer`. Does null mean "empty"? Is null only valid before some initialization? Does null indicate an error happened? Etc... `OptionalInt` has a specific *meaning*. – Radiodef Apr 11 '15 at 23:15

2 Answers2

6

Suppose you have a method

public void logRequest(Integer userID, String content){
    //log content locally or in db or a rest call
}

Suppose you obtain the userID from database for a particular user. There can be following possibilities:

  • DB returns a userID.
  • No id found.

So now if no id was found, what do you pass to logRequest?

  • Do you pass null? What if the method didnt have appropriate null check. What should it infer null to?
  • Should you pass 0 or -1? If null means 0 then it might contradict with an actual user whose ID is 0. How do you distinguish null and 0?

Of-course the above problem can be solved by proper documentation and fixing the rules, but it gives rise to higher maintenance and is error prone. And properly written code should be its own documentation.

Now say the method was declared as:

public void logRequest(OptionalInt userID, String content)

The method itself makes it very clear that it expects an argument which is optional. So there are only 2 case to handle: An appropriate argument is sent (which means no-bypassing by using 0). If the optional was empty, then method rightly knows how to handle. (Unlike before where we had to read its documentation to predict the behavior).

So the method declaration it self makes it clear on the behavior rather than documentation doing it for you and relying on documentation and wild-guessing. Optionals are quite useful in such scenarios.

PS: I always feel a pinch passing null to a method expecting an Integer. It definitely feels wrong! Gosh, in Java the sub-conscious mind always treats ints as primitives. They are not meant to be nulled.

Jatin
  • 31,116
  • 15
  • 98
  • 163
  • This is a very interesting answer. I have been told it is not optimal to pass Optionals as parameters to a method, and overloading should be used instead. However, in some situations like this the semantics make sense to pass optionals as arguments. – tmn Apr 10 '15 at 11:26
  • 2
    I think it is better to forget about optimality because such small things hardly impact performance :). But yes, I would prefer overriding in most of the cases as it is much cleaner. – Jatin Apr 10 '15 at 14:43
4

In the answers to the question you have linked, is an explanation about why primitive values can’t be null. There is not the slightest suggestion that using boxed values for representing null is “best practice”, in fact, it has not been said that using null is a good practice at all.

Instead of trying to emulate null values for primitive types you should take a step back and think about what you are going to express. That semantics might b expressed using a variety of options, using null not necessarily being one of the best choices. One simple way of expressing uninitialized or “cleared” values is to have an additional boolean fooPropertyInitialized variable. It’s much clearer than using null and its overhead is not necessarily bigger than boxing of primitive values.

That would also apply to the API. Don’t use Optional for a property. Just provide a clearFooProperty() method, if you want to support such an operation, plus an isFooPropertyInitialized(). It’s much cleaner to have getFooProperty() throwing an exception if the caller failed to check the initialized state first.

Note that’s also possible to simply use a value outside the range valid for a certain context to express special conditions. That’s common practice like InputStream.read() methods returning -1 to signal reaching the end.

Optional is the ideal return type for an operation whereas there is no storage for the result so you can’t split querying for the presence and the value into two method invocations and the value range of of present values is not limited.

But as said, without knowing what kind of semantics you want to express, we can’t make a recommendation and there might be more than one possible solution without a “best practice”…

Holger
  • 285,553
  • 42
  • 434
  • 765