3

Recently I had a discussion with my teammate on use of Guava Optional for optional parameters in a method.

Let's say method is

List<Book> getBooks(String catalogId, Optional<String> categoryId) {
     Validate.notNull(catalogId);
     Validate.notNull(categoryId); // Point of conflict. Is this required?

which accepts a catalogId and an optional categoryId which returns books listed in that catalog and if category is also passed then returns books only in that category.

Point of conflict was, Validating Optional<String> categoryId for null check. I was of view point that there should not be a null check on it since it's an optional parameter. Caller of the function can either pass null or Optional.<String>absent() and getBooks function should handle both cases by doing if(categoryId==null && categoryId.isPresent()) in the implementation.

My opinion was that Optional for optional parameters just makes the contract of the method more clear. One can tell just by looking at method signature that this parameter is optional and does not need to read the javadocs. But he should not be forced to pass Optional.absent() when he does not want to use that optional parameter.

My team mate had different view. He wanted to put a null check for it and hence force the caller to always pass Optional.<String>absent(). His point was that why would we pass a null optional. Moreover getBooks("catalog123", Optional.absent()) looks more readable than getBooks("catalog123", null).

This method is in one of our library packages and is used by multiple packages owned by us.

What are your suggestions on usage of Optional for this scenario?

Thanks

Mandar Pandit
  • 2,171
  • 5
  • 36
  • 58
RandomQuestion
  • 6,778
  • 17
  • 61
  • 97
  • 7
    If allowing `null`, you have in fact _three possible values_: no value (indicated by `null`), absent value (indicated by `Optional.absent()`), and a present value. I think, this is not intended, from what I can see in the method design. I think, you intended to differ between absent and present values. Two possibilities, that are clearly expressed by a non-null Optional. So, I would clearly go with your colleague. – Seelenvirtuose Jun 15 '14 at 07:44
  • 3
    To me, Optional is best used as a return value, to force the caller of a method to check for presence/absence, and to be able to differentiate between a present, null value, and an absent value. I would just use a String as optional parameter, document it as nullable, and annotate it with @Nullable. You could also provide an overloaded method with a single argument. If you stick with Optional, I'd be with your collegues, for the same reasons as Seelenvirtuose. – JB Nizet Jun 15 '14 at 08:04

1 Answers1

9

What are your suggestions on usage of Optional for this scenario?

Avoid. Avoid. Avoid.

While Optional is a cool alternative to null, in Java you'll always end up with it being a bad addition instead. As Seelenvirtuose wrote, there are three possibilities where you need only two. As JB Nizet wrote, it's best used as a return value, where it reminds the caller of the needed check. As a method argument, it doesn't help anything.

Ideally, an optional argument would be just optional like in

getBooks(String catalogId, String categoryId = null)

which is no valid Java. AFAIK the C++ compiler translates it into two methods

getBooks(String catalogId, String categoryId)
getBooks(String catalogId)

which is what you have to write in Java yourself. Leaving a parameter out is the clearest way of making clear that it's optional. Marking the optional argument as @Nullable is nearly as good. Using a nullability checking tool can help you avoid NPEs (which is the main argument for Optional).

What's important is consistency. Consistency across your classes is in your hands. Consistency with JDK means using null, at least for the foreseeable future (one day JDK 8 Optional may prevail).

maaartinus
  • 44,714
  • 32
  • 161
  • 320
  • afaik the C++ compiler just generates one method but adds the default value as a parameter when it's missing in the invocation – Remigius Stalder Jun 09 '15 at 11:41
  • @RemigiusStalder You may be right, however, it's equivalent to generating both methods and always inlining one of them. Actually, this makes a lot of sense w.r.t. the implementation. But for the user it's exactly as if there were two methods (not sure about complicated cases with overloading and inherited methods). – maaartinus Jun 09 '15 at 11:59
  • 1
    Exactly. The semantics are equivalent, but two signatures mandate more entry points. – Remigius Stalder Jun 09 '15 at 12:07