Uses for Optional
Asked Answered
S

14

360

Having been using Java 8 now for 6+ months or so, I'm pretty happy with the new API changes. One area I'm still not confident in is when to use Optional. I seem to swing between wanting to use it everywhere something may be null, and nowhere at all.

There seem to be a lot of situations when I could use it, and I'm never sure if it adds benefits (readability / null safety) or just causes additional overhead.

So, I have a few examples, and I'd be interested in the community's thoughts on whether Optional is beneficial.

1 - As a public method return type when the method could return null:

public Optional<Foo> findFoo(String id);

2 - As a method parameter when the param may be null:

public Foo doSomething(String id, Optional<Bar> barOptional);

3 - As an optional member of a bean:

public class Book {

  private List<Pages> pages;
  private Optional<Index> index;

}

4 - In Collections:

In general I don't think:

List<Optional<Foo>>

adds anything - especially since one can use filter() to remove null values etc, but are there any good uses for Optional in collections?

Any cases I've missed?

Smallpox answered 4/5, 2014 at 10:7 Comment(5)
One case I find useful is, for instance, if you have a substitution map. For instance Map<Character, String>. If there is no substitution I can use this: Optional.ofNullable(map.get(c)).orElse(String.valueOf(c)). Also note that Optional was stolen from Guava and it has a much nicer syntax: Optional.fromNullable(map.get(c)).or(String.valueOf(c));Rhnegative
Also, in collections, well, there are collections not allowing null values! Optional fits the bill in here. And you can .filter(Optional::absent) "null values" outRhnegative
@Rhnegative In all fairness, I think that the concept of Optional is actually stemming from FP.Calcicole
@Rhnegative isn't that better expressed with getOrDefault()?Alysiaalyson
A useful article about Optional may help: camelcodes.net/…Keenan
S
280

The main design goal of Optional is to provide a means for a function returning a value to indicate the absence of a return value. See this discussion. This allows the caller to continue a chain of fluent method calls.

This most closely matches use case #1 in the OP's question. Although, absence of a value is a more precise formulation than null since something like IntStream.findFirst could never return null.


For use case #2, passing an optional argument to a method, this could be made to work, but it's rather clumsy. Suppose you have a method that takes a string followed by an optional second string. Accepting an Optional as the second arg would result in code like this:

foo("bar", Optional.of("baz"));
foo("bar", Optional.empty());

Even accepting null is nicer:

foo("bar", "baz");
foo("bar", null);

Probably the best is to have an overloaded method that accepts a single string argument and provides a default for the second:

foo("bar", "baz");
foo("bar");

This does have limitations, but it's much nicer than either of the above.

Use cases #3 and #4, having an Optional in a class field or in a data structure, is considered a misuse of the API. First, it goes against the main design goal of Optional as stated at the top. Second, it doesn't add any value.

There are three ways to deal with the absence of a value in an Optional: to provide a substitute value, to call a function to provide a substitute value, or to throw an exception. If you're storing into a field, you'd do this at initialization or assignment time. If you're adding values into a list, as the OP mentioned, you have the additional choice of simply not adding the value, thereby "flattening" out absent values.

I'm sure somebody could come up with some contrived cases where they really want to store an Optional in a field or a collection, but in general, it is best to avoid doing this.

Shortfall answered 5/5, 2014 at 4:26 Comment(17)
Great answer - especially +1 for the link to the mailing list discussion. When first reading something about it - I had actually originally just assumed the new Optional value was intended to be used as a replacement for null values (i.e. intended to be used for all use cases described in the OP) but your answer shows that really is not the intention.Handicap
I disagree with #3. It can be useful to have an Optional as a field when things are to be done or not to be done upon presence or absence of a value.Mineraloid
Btw mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/… is a further disucssion (a year later) where not using Optional as a parateter is more clearly stated. It's nicely summarised in blog.jhades.org/java-8-how-to-use-optionalIthnan
@Handicap I hope returning Optional from a private method instead of null is also a valid case just like a public API. correct?Yarak
I don't see why doing if(foo == null) internally would be better than just storing the field as optional. And I don't see why explicitly calling getOptionalFoo() internally is better than just storing the field as an Optional. Also, if one field can be null and one field cannot be null, why not communicate that to the compiler by making them Optional or not Optional.Bounty
@Bounty If you want to use Optional as a field, you can; we just don't recommend it. If you do, I think you'll find that your code gets rather cluttered and hard to read. Also, Optional is another object, so every field that's an Optional consumes more space and costs an extra pointer deference. But if you're ok with these issues, go ahead.Shortfall
@stuartmarks I think what I am trying to emphasis is that it's easier to read, because you are being told whether a field can be null or not and the compiler is making you account for it. So if you are forced to use the optional object you'll be forced to account for avoiding null. If it's not optional, you can assume it's never null and not do the check. This is the rule of thumb I follow. I agree about space and pointer dereferencing, but doubt many developers work on applications where they have to worry about performance to that level. I may just be naive though.Bounty
@StuartMarks, this is one of the things that just baffles me when I hear it from all the Optional<> experts: "don't store Optional<> in a field". I'm truly trying to understand the point of this recommendation. Consider a DOM tree where a node could have a parent or not. It seems within the use case that Node.getParent() would return Optional<Node>. Am I really expected to store a null and wrap the result each time? Why? What does this extra inefficiency buy me, other than making my code look ugly?Penland
@GarretWilson If you've determined that using Optional for fields is more efficient for your use case, and doing so makes your code look good, then fine, go ahead and use it. I can't see your code. But I have to say I'm a bit skeptical. Using your example, suppose you have a DOM tree with N nodes. If you have Optional<Node> parent instead of a nullable Node parent field, then you've just doubled the number of objects in your DOM tree. It probably also reduces locality of reference significantly, causing a bunch more cache misses during traversal.Shortfall
@GarretWilson On the other hand, suppose you have Optional<Node> getParent() { return Optional.ofNullable(parent); }. This looks expensive because it allocates an Optional every time! But if the caller unpacks it immediately, the object is extremely short-lived and is never promoted out of eden space. It might possibly even be eliminated by the JIT's escape analysis. The bottom line answer is "it depends" as always, but using Optional in fields potentially bloats memory use and slows down data structure traversal. And finally I think it clutters up code, but this is a matter of taste.Shortfall
@StuartMarks "if the caller unpacks it immediately"---yes, that seems to be another assumption that was made with Java 8, as only in Java 9 are we getting things such as Optional.or(), which finally realizes that many times the thing getting the optional is going to turn it around and pass it to something else. It seems silly (and wasteful) to be bouncing back and forth between "unpacking" and "Optional.ofNullable()ing" as we unwind the stack---not to mention bringing back the danger of accidentally referencing a null, which is what Optional was supposed to prevent in the first place.Penland
@StuartMarks, my actual use case was an i18n resource lookup facility that had an optional parent resolver, which would then be passed to the constructor of the actual resource lookup instance by the factory. Looking up resources in real time is not where we want to be bouncing between wrapped/unwrapped Optional<>s. But at this point I should stop with the Stack Overflow comments and write a blog entry. :)Penland
@GarretWilson So did you write a blog for that? I would be interested in that :)Bega
There is a contradiction in the information provided about Optional fields. In "Java 8 in Action", they literally use Optional fields as the first example and benefit. This book was written by Java designers who I assume work beneath you (Stuart) and Brian? Also in my experience there are cases where it makes sense. E.g. the absence of an Http proxy.Reifel
@Bega blog.codefx.org/techniques/…Schoof
“and costs an extra pointer deference”—I wouldn’t be using Java if I cared about “an extra pointer dereference” (or twelve).Osborn
@Reifel directly from the book’s description on Amazon: “Raoul-Gabriel Urma is CEO of Cambridge Spark. Mario Fusco is a senior software engineer at Red Hat. Alan Mycroft is a University of Cambridge computer science professor” Where did you get the story from that either of them was a JDK developer?Nurserymaid
C
132

I'm late to the game but for what it's worth, I want to add my 2 Cents. They go against the design goal of Optional, which is well summarized by Stuart Marks's answer, but I'm still convinced of their validity (obviously).

Use Optional Everywhere

In General

I wrote an entire blog post about using Optional but it basically comes down to this:

  • design your classes to avoid optionality wherever feasibly possible
  • in all remaining cases, the default should be to use Optional instead of null
  • possibly make exceptions for:
    • local variables
    • return values and arguments to private methods
    • performance critical code blocks (no guesses, use a profiler)

The first two exceptions can reduce the perceived overhead of wrapping and unwrapping references in Optional. They are chosen such that a null can never legally pass a boundary from one instance into another.

Note that this will almost never allow Optionals in collections which is almost as bad as nulls. Just don't do it. ;)

Regarding your questions

  1. Yes.
  2. If overloading is no option, yes.
  3. If other approaches (subclassing, decorating, ...) are no option, yes.
  4. Please no!

Advantages

Doing this reduces the presence of nulls in your code base, although it does not eradicate them. But that is not even the main point. There are other important advantages:

Clarifies Intent

Using Optional clearly expresses that the variable is, well, optional. Any reader of your code or consumer of your API will be beaten over the head with the fact that there might be nothing there and that a check is necessary before accessing the value.

Removes Uncertainty

Without Optional the meaning of a null occurrence is unclear. It could be a legal representation of a state (see Map.get) or an implementation error like a missing or failed initialization.

This changes dramatically with the persistent use of Optional. Here, already the occurrence of null signifies the presence of a bug. (Because if the value were allowed to be missing, an Optional would have been used.) This makes debugging a null pointer exception much easier as the question of the meaning of this null is already answered.

More Null Checks

Now that nothing can be null anymore, this can be enforced everywhere. Whether with annotations, assertions or plain checks, you never have to think about whether this argument or that return type can be null. It can't!

Disadvantages

Of course, there is no silver bullet...

Performance

Wrapping values (especially primitives) into an extra instance can degrade performance. In tight loops this might become noticeable or even worse.

Note that the compiler might be able to circumvent the extra reference for short lived lifetimes of Optionals. In Java 10 value types might further reduce or remove the penalty.

Serialization

Optional is not serializable but a workaround is not overly complicated.

Invariance

Due to the invariance of generic types in Java, certain operations become cumbersome when the actual value type is pushed into a generic type argument. An example is given here (see "Parametric polymorphism").

Cecilia answered 21/11, 2014 at 22:39 Comment(8)
Another disadvantage (or limitation) is that you cannot sort Optional(xxx) instances, though Oracle clearly imposed that restriction deliberately. I'm skeptical about the wisdom of having these classes available where they should only be used in specific circumstances, and assuming the developer will do the right thing. Solving one problem may cause another. Maybe there should be compiler warnings to aid the developer when using the Optional(xxx) classes in "undesirable" ways (e.g. as method parameters, in collections, in constructors, etc.) if that really is not intended usage?Exoergic
About 4, optionals in collections: It is actually sometimes useful to store optionals in Lists. This is the case when it is important that a certain element is located at a certain index, but the element can be present or not. That is clearly communicated by a List<Optional<T>> type. If on the other hand it is only important which objects that are members some some collection then there is not point.Chilli
I think use-case #2 is still very questionable. An Optional being passed into a method can be null. So what have you gained? Now you have two checks to make. See https://mcmap.net/q/18132/-why-should-java-8-39-s-optional-not-be-used-in-argumentsSwetiana
@DavidV look at the list of advantages I gave - they all apply to that case as well. Besides, if you go all in on Optional (which should be the case if you're willing to pass it as arguments) null is never a legal value. So calling a method with an explicit parameter null is obviously a mistake.Cecilia
“Wrapping values (especially primitives)…”—What about e.g. OptionalInt? I don’t see how that’s worse than wrapping an int in a (nullable) Integer.Osborn
@Osborn You're right, it's not worse than wrapping into Integer. It's the same, which is why you'd want to prevent both in high performance situations.Cecilia
Strongly disagree. Optional has several disadvantages: it breaks the bean contract (can't have a setter of String and getter of Optional<String>). Optional.ifPresent(() -> xyz) is far harder for me personally to read. I find type nullability far better solution; using @NotNull moves Java towards type nullability and makes it compatible with Kotlin. As Brian Goetz mentioned: Optional is intended to provide a limited mechanism for library method return types where there is a clear need to represent “no result,” and where using null for that is overwhelmingly likely to cause errors.Dave
@MartinVysny This opinion is surely in the minority but I have been using this approach for years now and it has been great. The only tool I need to be save from null is a few null checks and the compiler. I'm really glad I don't have to deal with Beans nor much imperative code that requires ifPresent (it's mostly map/flatMap/orElse... for me). And I am aware that this is against Brian Goetz' (and Stuart Marks' - see above) recommendation, but as I said: It has been working great for me, so I see no reason to stop doing it. 😁Cecilia
I
44

Personally, I prefer to use IntelliJ's Code Inspection Tool to use @NotNull and @Nullable checks as these are largely compile time (can have some runtime checks) This has lower overhead in terms of code readability and runtime performance. It is not as rigorous as using Optional, however this lack of rigour should be backed by decent unit tests.

public @Nullable Foo findFoo(@NotNull String id);

public @NotNull Foo doSomething(@NotNull String id, @Nullable Bar barOptional);

public class Book {

  private List<Pages> pages;
  private @Nullable Index index;

}

List<@Nullable Foo> list = ..

This works with Java 5 and no need to wrap and unwrap values. (or create wrapper objects)

Inspiration answered 4/5, 2014 at 10:17 Comment(5)
Uhm, are those IDEA annotations? I prefer JSR 305's @Nonnull personally -- works with FindBugs ;)Rhnegative
@Rhnegative There is a lack of standards in this regard, but I believe the tools are generally configurable and you don't have to end up with @Nonnull @NotNull etcInspiration
Yes that is true; IDEA (13.x) gives three different choices... Meh, I always end up using JSR 305 anywaRhnegative
I know this is old, but the discussion about annotations & tools deserves a link to stackoverflow.com/questions/35892063/… - which btw specifically addresses the case of Java 8.Corporate
…as of 2021-01-29, this should be upvoted 192 another times.Footwall
E
30

I think the Guava Optional and their wiki page puts it quite well:

Besides the increase in readability that comes from giving null a name, the biggest advantage of Optional is its idiot-proof-ness. It forces you to actively think about the absent case if you want your program to compile at all, since you have to actively unwrap the Optional and address that case. Null makes it disturbingly easy to simply forget things, and though FindBugs helps, we don't think it addresses the issue nearly as well.

This is especially relevant when you're returning values that may or may not be "present." You (and others) are far more likely to forget that other.method(a, b) could return a null value than you're likely to forget that a could be null when you're implementing other.method. Returning Optional makes it impossible for callers to forget that case, since they have to unwrap the object themselves for their code to compile. -- (Source: Guava Wiki - Using and Avoiding null - What's the point?)

Optional adds some overhead, but I think its clear advantage is to make it explicit that an object might be absent and it enforces that programmers handle the situation. It prevents that someone forgets the beloved != null check.

Taking the example of 2, I think it is far more explicit code to write:

if(soundcard.isPresent()){
  System.out.println(soundcard.get());
}

than

if(soundcard != null){
  System.out.println(soundcard);
}

For me, the Optional better captures the fact that there is no soundcard present.

My 2¢ about your points:

  1. public Optional<Foo> findFoo(String id); - I am not sure about this. Maybe I would return a Result<Foo> which might be empty or contain a Foo. It is a similar concept, but not really an Optional.
  2. public Foo doSomething(String id, Optional<Bar> barOptional); - I would prefer @Nullable and a findbugs check, as in Peter Lawrey's answer - see also this discussion.
  3. Your book example - I am not sure if I would use the Optional internally, that might depend on the complexity. For the "API" of a book, I would use an Optional<Index> getIndex() to explicitly indicate that the book might not have an index.
  4. I would not use it in collections, rather not allowing null values in collections

In general, I would try to minimize passing around nulls. (Once burnt...) I think it is worth to find the appropriate abstractions and indicate to the fellow programmers what a certain return value actually represents.

Eldrid answered 4/5, 2014 at 11:56 Comment(4)
You would write soundcard.ifPresent(System.out::println). Calling isPresent is semantically the same as checking for null.Stipulate
The issue to me is that things with Optional types can still be null. So to actually be completely safe you have to do something like if(soundcard != null && soundcard.isPresent()). Though making an api that returns an Optional and could also return null is something I hope no one ever does.Ricketts
"It forces you to actively think about the absent case if you want your program to compile at all, since you have to actively unwrap the Optional and address that case." I'm not really sure how it forces this, though I don't work in Java a whole lot. Could you explain what Java does to force you to unwrap AND check the !isPresent case simply to compile?Klystron
what I never understood: We are expected to forget !=null, but we never forget .isPresent?Footwall
P
19

From Oracle tutorial:

The purpose of Optional is not to replace every single null reference in your codebase but rather to help design better APIs in which—just by reading the signature of a method—users can tell whether to expect an optional value. In addition, Optional forces you to actively unwrap an Optional to deal with the absence of a value; as a result, you protect your code against unintended null pointer exceptions.

Pursuit answered 31/5, 2016 at 7:53 Comment(2)
APIs just for the return part of the method, right? Optionals shouldn't be used as parameters because of type-erasure ? sometimes I use an Optional internally in a method, converted from a nullable parameter or as a field initialize from a null constructor parameter ... still trying to figure out if that is more useful than just leaving it as null - anyone have any thoughts?Calzada
@Calzada You can find quite much information about those cases in this or that question. Answers to those questions tell much more than what was asked about and cover other cases. For more info, browse more or ask your own question, because probably you won't get much attention here. ; )Pursuit
P
17

In java, just don't use them unless you are addicted to functional programming.

They have no place as method arguments (I promess someone one day will pass you a null optional, not just an optional that is empty).

They make sense for return values but they invite the client class to keep on stretching the behavior-building chain.

FP and chains have little place in an imperative language like java because it makes it very hard to debug, not just to read. When you step to the line, you can't know the state nor intent of the program; you have to step into to figure it out (into code that often isn't yours and many stack frames deep despite step filters) and you have to add lots of breakpoints down to make sure it can stop in the code/lambda you added, instead of simply walking the if/else/call trivial lines.

If you want functional programming, pick something else than java and hope you have the tools for debugging that.

Portillo answered 4/10, 2019 at 0:2 Comment(1)
I totally agree. Optional is a gimmick.Breuer
S
14

1 - As a public method return type when the method could return null:

Here is a good article that shows usefulness of usecase #1. There this code

...
if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String isocode = country.getIsocode();
            isocode = isocode.toUpperCase();
        }
    }
}
...

is transformed to this

String result = Optional.ofNullable(user)
  .flatMap(User::getAddress)
  .flatMap(Address::getCountry)
  .map(Country::getIsocode)
  .orElse("default");

by using Optional as a return value of respective getter methods.

Sumikosumma answered 3/10, 2018 at 11:37 Comment(2)
In my opinion, the first example is much more readable than the transformed example. Also the first example could have only one if statement instead of 3.Emphasis
This example assumes that the getters are returning an Optional. Returning an on getters is not advised by anyone, Oracle included.Toughen
R
3

Here is an interesting usage (I believe) for... Tests.

I intend to heavily test one of my projects and I therefore build assertions; only there are things I have to verify and others I don't.

I therefore build things to assert and use an assert to verify them, like this:

public final class NodeDescriptor<V>
{
    private final Optional<String> label;
    private final List<NodeDescriptor<V>> children;

    private NodeDescriptor(final Builder<V> builder)
    {
        label = Optional.fromNullable(builder.label);
        final ImmutableList.Builder<NodeDescriptor<V>> listBuilder
            = ImmutableList.builder();
        for (final Builder<V> element: builder.children)
            listBuilder.add(element.build());
        children = listBuilder.build();
    }

    public static <E> Builder<E> newBuilder()
    {
        return new Builder<E>();
    }

    public void verify(@Nonnull final Node<V> node)
    {
        final NodeAssert<V> nodeAssert = new NodeAssert<V>(node);
        nodeAssert.hasLabel(label);
    }

    public static final class Builder<V>
    {
        private String label;
        private final List<Builder<V>> children = Lists.newArrayList();

        private Builder()
        {
        }

        public Builder<V> withLabel(@Nonnull final String label)
        {
            this.label = Preconditions.checkNotNull(label);
            return this;
        }

        public Builder<V> withChildNode(@Nonnull final Builder<V> child)
        {
            Preconditions.checkNotNull(child);
            children.add(child);
            return this;
        }

        public NodeDescriptor<V> build()
        {
            return new NodeDescriptor<V>(this);
        }
    }
}

In the NodeAssert class, I do this:

public final class NodeAssert<V>
    extends AbstractAssert<NodeAssert<V>, Node<V>>
{
    NodeAssert(final Node<V> actual)
    {
        super(Preconditions.checkNotNull(actual), NodeAssert.class);
    }

    private NodeAssert<V> hasLabel(final String label)
    {
        final String thisLabel = actual.getLabel();
        assertThat(thisLabel).overridingErrorMessage(
            "node's label is null! I didn't expect it to be"
        ).isNotNull();
        assertThat(thisLabel).overridingErrorMessage(
            "node's label is not what was expected!\n"
            + "Expected: '%s'\nActual  : '%s'\n", label, thisLabel
        ).isEqualTo(label);
        return this;
    }

    NodeAssert<V> hasLabel(@Nonnull final Optional<String> label)
    {
        return label.isPresent() ? hasLabel(label.get()) : this;
    }
}

Which means the assert really only triggers if I want to check the label!

Rhnegative answered 5/5, 2014 at 5:53 Comment(0)
S
3

Optional class lets you avoid to use null and provide a better alternative:

  • This encourages the developer to make checks for presence in order to avoid uncaught NullPointerException's.

  • API becomes better documented because it's possible to see, where to expect the values which can be absent.

Optional provides convenient API for further work with the object: isPresent(); get(); orElse(); orElseGet(); orElseThrow(); map(); filter(); flatmap().

In addition, many frameworks actively use this data type and return it from their API.

Snood answered 18/11, 2018 at 12:10 Comment(0)
O
3

Here are some of the methods that you can perform on an instance of Optional<T>:

  • map
  • flatMap
  • orElse
  • orElseThrow
  • ifPresentOrElse
  • get

Here are all the methods that you can perform on null:

  • (there are none)

This is really an apples to oranges comparison: Optional<T> is an actual instance of an object (unless it is null… but that would probably be a bug) while null is an aborted object. All you can do with null is check whether it is in fact null, or not. So if you like to use methods on objects, Optional<T> is for you; if you like to branch on special literals, null is for you.

null does not compose. You simply can’t compose a value which you can only branch on. But Optional<T> does compose.

You can, for instance, make arbitrary long chains of “apply this function if non-empty” by using map. Or you can effectively make an imperative block of code which consumes the optional if it is non-empty by using ifPresent. Or you can make an “if/else” by using ifPresentOrElse, which consumes the non-empty optional if it is non-empty or else executes some other code.

…And it is at this point that we run into the true limitations of the language in my opinion: for very imperative code you have to wrap them in lambdas and pass them to methods:

    opt.ifPresentOrElse(
            string -> { // if present...
                // ...
            }, () -> { // or else...
                // ...
            }
    );

That might not be good enough for some people, style-wise.

It would be more seamless if Optional<T> was an algebraic data type that we could pattern match on (this is obviously pseudo-code:

    match (opt) {
        Present(str) => {
            // ...
        }
        Empty =>{
            // ...
        }
    }

But anyway, in summary: Optional<T> is a pretty robust empty-or-present object. null is just a sentinel value.

Subjectively disregarded reasons

There seems to be a few people who effectively argue that efficiency should determine whether one should use Optional<T> or branch on the null sentinel value. That seems a bit like making hard and fast rules on when to make objects rather than primitives in the general case. I think it’s a bit ridiculous to use that as the starting point for this discussion when you’re already working in a language where it’s idiomatic to make objects left-and-right, top to bottom, all the time (in my opinion).

Osborn answered 9/7, 2020 at 18:18 Comment(0)
H
2

An Optional has similar semantics to an unmodifiable instance of the Iterator design pattern:

  • it might or might not refer to an object (as given by isPresent())
  • it can be dereferenced (using get()) if it does refer to an object
  • but it can not be advanced to the next position in the sequence (it has no next() method).

Therefore consider returning or passing an Optional in contexts where you might previously have considered using a Java Iterator.

Hannelorehanner answered 25/2, 2019 at 12:33 Comment(0)
H
1

I do not think that Optional is a general substitute for methods that potentially return null values.

The basic idea is: The absence of a value does not mean that it potentially is available in the future. It's a difference between findById(-1) and findById(67).

The main information of Optionals for the caller is that he may not count on the value given but it may be available at some time. Maybe it will disappear again and comes back later one more time. It's like an on/off switch. You have the "option" to switch the light on or off. But you have no option if you do not have a light to switch on.

So I find it too messy to introduce Optionals everywhere where previously null was potentially returned. I will still use null, but only in restricted areas like the root of a tree, lazy initialization and explicit find-methods.

Haste answered 31/3, 2017 at 20:30 Comment(0)
P
1

1 - As a public method return type when the method could return null:

This is the intended use case for Optional, as seen in the JDK API docs:

Optional is primarily intended for use as a method return type where there is a clear need to represent "no result," and where using null is likely to cause errors.

Optional represents one of two states:

  1. it has a value (isPresent returns true)
  2. it doesn't have a value (isEmpty returns true)

So if you have a method that returns either something or nothing, this is the ideal use case for Optional.

Here's an example:

Optional<Guitarist> findByLastName(String lastName);

This method takes a parameter used to search for an entity in the database. It's possible that no such entity exists, so using an Optional return type is a good idea since it forces whoever is calling the method to consider the empty scenario. This reduces chances of a NullPointerException.

2 - As a method parameter when the param may be null:

Although technically possible, this is not the intended use case of Optional.

Let's consider your proposed method signature:

public Foo doSomething(String id, Optional<Bar> barOptional);

The main problem is that we could call doSomething where barOptional has one of 3 states:

  1. an Optional with a value e.g. doSomething("123", Optional.of(new Bar())
  2. an empty Optional e.g. doSomething("123", Optional.empty())
  3. null e.g. doSomething("123", null)

These 3 states would need to be handled in the method implementation appropriately.

A better solution is to implement an overloaded method.

public Foo doSomething(String id);

public Foo doSomething(String id, Bar bar);

This makes it very clear to the consumer of the API which method to call, and null does not need to be passed.

3 - As an optional member of a bean:

Given your example Book class:

public class Book {
  private List<Pages> pages;
  private Optional<Index> index;
}

The Optional class variable suffers from the same issue as the Optional method parameter discussed above. It can have one of 3 states: present, empty, or null.

Other possible issues include:

  • serialization: if you implement Serializable and try to serialize an object of this class, you will encounter a java.io.NotSerializableException since Optional was not designed for this use case
  • transforming to JSON: when serializing to JSON an Optional field may get mapped in an undesirable way e.g. {"empty":false,"present":true}. Although if you use the popular Jackson library, it does provide a solution to this problem.

Despite these issues, Oracle themselves published this blog post at the time of the Java 8 Optional release in 2014. It contains code examples using Optional for class variables.

public class Computer {
  private Optional<Soundcard> soundcard;  
  public Optional<Soundcard> getSoundcard() { ... }
  ...
}

In the following years though, developers have found better alternatives such as implementing a getter method to create the Optional object.

public class Book {
    private List<Pages> pages;
    private Index index;
    public Optional<Index> getIndex() {
        return Optional.ofNullable(index);
    }
}

Here we use the ofNullable method to return an Optional with a value if index is non-null, or otherwise an empty Optional.

4 - In Collections:

I agree that creating a List of Optional (e.g. List<Optional<Foo>>) doesn't add anything. Instead, just don't include the item in the List if it's not present.

Puzzlement answered 11/7, 2022 at 10:14 Comment(0)
P
0

Seems Optional is only useful if the type T in Optional is a primitive type like int, long, char, etc. For "real" classes, it does not make sense to me as you can use a null value anyway.

I think it was taken from here (or from another similar language concept).

Nullable<T>

In C# this Nullable<T> was introduced long ago to wrap value types.

Paniculate answered 4/5, 2014 at 10:13 Comment(7)
It is a ripoff of Guava's Optional in factRhnegative
@Rhnegative OK but when this was present in C# (2005, MS.NET 2.0), there was no Guava, I think. And ... who knows where C# took this from.Paniculate
@Rhnegative "Ripoff of Guava's Optional" is kind of a funny way to put it, since the Guava guys participated in discussions, provided their experiences, and generally were in favor of java.util.Optional.Shortfall
@StuartMarks yes, and Guava has had Optional for quite some time before discussions of it making into Java 8 even began ;) And the same holds true for, for instance, Function, Supplier and PredicateRhnegative
@Rhnegative No doubt Java's APIs were strongly influenced by Guava's. I'm taking issue with "ripoff" which sounds like stealing. The Guava guys contributed a lot of valuable ideas to Java 8.Shortfall
You're missing the point. Optional is to be used instead of returning null. It is safer than potentially throwing a NullPointerException. See: oracle.com/technetwork/articles/java/…Dermatome
@Paniculate Optional is only useful if the type T in Optional is a primitive For that I can use a wrapper type, it allows returning a null.Thicken

© 2022 - 2024 — McMap. All rights reserved.