Optional Method Parameters

I have recently come across an interesting problem: should you use Optional as a method parameter type? The majority of sources says that you shouldn’t, but let’s weigh the arguments before making a verdict.

Why not just pass nulls around?

Before we get into the case of using Optional, we should understand why do we even have this problem. We could just pass nulls around, right? Well, not quite. As I’ve written in my post about null handling, you should never pass null as an argument to a public method. It’d require you to read all the code down the call stack to make sure that null value is actually supported and won’t blow the application. And once you’d do that, the callee code could not be modified in any way that does not support null, which is a rather unwanted constraint. Therefore, you need another solution in case one of the parameters is missing.

Now, that we’re done with nulls, let’s evaluate using the Optional type.

“It was not meant to be used like this”

The majority of articles that I read and even my fantastic IDE point out that Optional as a method argument is bad because the original intent of creating Optional was to:

[..] provide a limited mechanism for library method return types where there needed to be a clear way to represent “no result”.

I’m sorry to say this, but this is a really bad argument. If there would be arguments for using Optional as a parameter type that outweigh the arguments against, it would only mean that the class is better than it intended to be and everyone should be happy. It’s like saying that you should not use a bread knife to open a package in your kitchen because the bread knife was not meant to do this.

“It causes conditional logic inside methods”

The source of this argument is the top answer in a related question on StackOverflow. To quote the original author:

Using Optional parameters causing conditional logic inside the methods is literally contra-productive.

This argument refers to a situation when you use Optional as a method parameter just to do conditional logic based on its presence:

It is an argument, but a limited one. The first limitation that I see is that oftentimes you would not do any conditional logic on the argument, you just want to pass it through:

The second limitation is that the only reasonable alternative that you have in most cases is method overloading. Then, if a client has a potential null on his side, he’s forced to do the conditional logic himself:

This, depending on the case might be a good thing or a bad thing.

“It’s still perfectly possible to pass in null to a method”

That’s a quote from another StackOverflow answer. I’d say that it can be an argument against Optional in general, but not solely against Optional arguments as you can return a null instead of Optional too. As a general argument, it still seems weak as we’re not talking about a dangerous toy for a kid, we’re talking about programmers (smart guys, you know?). If we followed this logic, we’d have to say that using Java is unsafe as you can do almost anything via reflection. Would that stop you from using Java? Obviously not.

“Function does more than one thing”

Ah, us clean coders! Such a good movement, but sometimes we tend to overdo things. But yes, that could be a code smell, especially if that one thing would be the conditional logic we talked about earlier. I’m not so sure if it would be so evil if the logic looked like this:

Does it still do more than one thing? Maybe. Is that bad for your codebase? Hard to judge, you’d have to consider other forces.

“The client code has to explicitly wrap”

Now, we’re on the client side of things and it seems like a valid argument. If the client has the value and knows that it’s surely not null, wrapping it into an optional might seem like a waste.

On the other hand, we’ve shown already that if the client has a potential null in hand, he might get even more complexity if we opt for overloading. Just look at the first client example above and compare it to this one:

Also, don’t forget that the client can leverage static imports to control the complexity of the invocation.

To conclude this argument, know your clients! A safe approach would be to choose one depending on the client’s needs. If you don’t know all your clients e.g. in a case of library code, you should probably stick to overloading.

“[..] imagine having two or three”

Daniel Olszewski, in his article titled Java 8 Optional Use Cases, argues that the case of Optional method parameters is much worse in the case of multiple such parameters. My intuition suggests that this could be the case, but I can’t come up with a good example. He does not provide any examples or reasoning for such state of things, just:

Uncle Bob definitely wouldn’t be proud of such code

All due respect to Uncle Bob, that’s not a valid argument. I’d say that you should apply common sense and other known guidelines to figure out what’s the best in such case.

We’re done with the arguments against Optional method parameters that I found online. Let me augment those with some of my recent reasoning.

Pass-thru Optional

Imagine that one of your API parameters is optional and it’s represented by a null. The data from your API is supposed to go from the controller, through application and domain services down to the deeps of your domain model. And it’s only the domain model that knows the “reasonable default” for that field e.g. null, which you shouldn’t pass around or some boundary value like MAX_INT. Obviously, you could just make this default value a public constant and pass it in the controller. But do you really want to couple the controller to an implementation detail of your domain class, especially if that would mean passing a null around? I don’t.

This is the case that we’ve already seen in the argument about conditional logic. The Optional is supposed to pass through down the call stack to be handled by the class that actually knows what to do it. In our case it would look like this:

I will skip the overloading version for brevity (you can see it in this gist), but it’s much longer and less expressive. Instead of stating clearly in the code: this parameter is optional, we’re adding a complexity of multiple analogous overloads. And it’s just for one such parameter, “imagine having two or three”!

What’s more testable?

This question is the reason why I started the research and then decided to write this article. If we consider overloading the right alternative to Optional method parameters, we’re might end up with a lot of unnecessary tests.

Let’s say that our method (and the private ones that it calls) has 2 testable side-effects and 1 error case in which it throws an exception. If I were to write tests for this method, it would look more or less like this:

That’s already a decent amount of code. Now, imagine testing the two overloaded methods… I don’t want to make you scroll down in annoyance but if someone wants to see it, I created a gist. And with all that being said, let’s once again “imagine having two or three”.

Conclusion

There are some valid arguments against using Optional as method parameter type, but to me, they are not good enough to be able to say with confidence that you should avoid it at all cost. And don’t forget there are also arguments for using Optional this way. I’d say that you should keep each of them in the back of your head and evaluate things on a case by case basis. Like always, it’s an it depends problem and it requires a bit of programming sense.

If you have any additional arguments for or against using Optional as method parameter type, let me know in comments!

About the Author Grzegorz Ziemoński

King of Tidy Java, nerd that thinks about producing perfect software all the time and proud owner of 2 cats.

follow me on:
  • Jacek Bilski

    Hi Grzegorz,

    I must honestly say, that I’m also struggling with this topic. In some places I was explicitly passing an Optional around to clearly state, that this part of my domain can be empty. Today I’d probably create a subclass, that would model the behaviour in case where this field was empty. Maybe only then I would be able to see which solution is better.
    I’m also wondering if using Optional as a monad is not actually a better approach. It might be a monad exactly for that reason. Then you’re writing

    instead of

    or

    Using such approach you don’t need to pass an Optional around that often. OK, I admit, ‘else’ part you can’t do it this way, but then again I think that most of the time there is no ‘else’.

  • GAUTAM SINGH

    I beg to differ. In my opinion not using optional as method argument is a well thought of trade off. Method is a bounded context where you can properly handle null scenario. But by accepting an optional you are forcing the caller to create this new object. If you are developing an API it is horrible thing, but if it’s internal method I guess it’s alright.

  • Simon Gwerder

    Just use @Nullable or @NonNull. Much cleaner contract with same effect.

  • Colin Hunt

    “If we followed this logic, we’d have to say that using Java is unsafe as you can do almost anything via reflection. Would that stop you from using Java? Obviously not.”

    Actually, it should. Java is a fundamentally unsafe language even for other reasons beyond reflection and it’s time we move on to more modern ones that A) are declarative, B) are immutable, C) do not allow runtime errors, D) do not allow anything to be null.

  • Ganesh