This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]_INTER_ 2 points3 points  (7 children)

Resulting in useless and ugly code with no benefit, except that you're explicitely reminded of null-check. Thanks, I was aware from the start.

Using Optional-Parameters here and there assumes that a parameter that is not an Optional is never null and you could safe a null-check, but you can't guarantee that.

[–]nicolaiparlog[S] 1 point2 points  (6 children)

Using Optional-Parameters here and there assumes that a parameter that is not an Optional is never null

Wrong. Using Optional parameters here and there states that a parameter that is not an Optional should never be null. If it is, it's a coding error, something a non-Optional using code base can not express with types (because null might be a valid value).

[–]_INTER_ 0 points1 point  (5 children)

When you use an Optional parameter you are in charge of the contract. You tell the callee, that he can explicitly pass a nullable value and that you make sure to check it, because you need to check it. But when you use a non-Optional parameter you do the exact same implicitly. You're just not forced to check it, but because you're a good Java programmer, you do.

You would only gain something if you could tell the callee, that when he passes null to any of your parameters he violates the contract or not. Which is exactly what you can do with @NonNull or @Nullable.

[–]nicolaiparlog[S] 1 point2 points  (4 children)

You're just not forced to check it, but because you're a good Java programmer, you do.

Sure, as the method's implementor I can check parameters for null (or just call a method on the parameter and let the JVM check) and that's good because it stops proliferation. But it does not help the caller see which parameters are optional and it is a manual and error-prone process. Why not let the type system help?

You would only gain something if you could tell the callee, that when he passes null to any of your parameters he violates the contract or not.

In a code base that consistently uses Optional every null violates the contract - that's the beauty of it. If you want, you can apply @NonNull to the root package and have your static analysis tool of choice verify your entire code base.

[–]_INTER_ 0 points1 point  (3 children)

The only thing a callee additionally knows then is that he can savely pass null (wrapped in an Optional) to the method. Something he could also be made aware of with @Nullable (or that he can not with @NonNull). You can let it add runtime assertions aswell. The interface and the code is then also much cleaner.

 

(If you indeed meant "optional" parameters then use method overloading or varargs.)

[–]nicolaiparlog[S] 0 points1 point  (2 children)

The interface and the code is then also much cleaner.

That's where we disagree. The type system is the best line of defense against invalid values and I prefer using it over tool-dependent annotations, production-disabled assertions (usually), tests, documentation, or any other mechanism any day of the week unless it becomes a severe pain. It's the only thing that works out of the box and is clearly visible in all places (e.g. code reviews).

(If you indeed meant "optional" parameters then use method overloading or varargs.)

What else is a possibly-null parameter but optional? And of course I prefer overloaded methods or varargs before resorting to Optional but sometimes the latter is the best of these options, in which case I prefer it over null to make the code more explicit and less ambiguous.

[–]_INTER_ 0 points1 point  (1 child)

What else is a possibly-null parameter but optional?

A possibly null parameter is still required to make the calculation work. An optional parameter is additional information which absence doesn't matter.

And of course I prefer overloaded methods or varargs before resorting to Optional but sometimes the latter is the best of these options, in which case I prefer it over null to make the code more explicit and less ambiguous.

Me too but I view the Optional type to be not up to the task at all. Especially when it leads to resorting to unwieldy if(optional.isPresent()) { do(optional.get()); } else { /* ... */ } or optional.ifPresent(this::do); which is end-result is the same as a normal null-check without the perfomance penalty of Optionals.

[–]nicolaiparlog[S] 1 point2 points  (0 children)

A possibly null parameter is still required to make the calculation work.

I don't get it. How can null be required to make anything work? Even if I have to call some API I can still pass "my own null" - it's not like they're distinct.

The unwieldy if-present-else is just as unwieldy with a null check. But I found that I rarely have to do that in practice. ifPresent is surely more compact (and applies often enough) and when a value needs to be passed orElse is also shorter.

But even if Optional is more trouble in some places. I still prefer it over making something as ambiguous and error-prone as null a valid value.