Uses for Optional

2018-12-31 05:38发布

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?

13条回答
几人难应
2楼-- · 2018-12-31 06:10

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").

查看更多
深知你不懂我心
3楼-- · 2018-12-31 06:11

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)

查看更多
旧时光的记忆
4楼-- · 2018-12-31 06:15

Java SE 8 introduces a new class called java.util.Optional,

You can create an empty Optional or Optional with null value.

Optional<String> emptyOptional= Optional.empty(); 

And here is an Optional with a non-null value:

String valueString = new String("TEST");
Optional<String > optinalValueString = Optional.of(valueString );

Do Something If a Value Is Present

Now that you have an Optional object, you can access the methods available to explicitly deal with the presence or absence of values. Instead of having to remember to do a null check, as follows:

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

You can use the ifPresent() method, as follows:

Optional<String> optinalString= null;
optinalString.ifPresent(System.out::println);



package optinalTest;

import java.util.Optional;

public class OptionalTest {

    public Optional<String> getOptionalNullString() {
        return null;
//      return Optional.of("TESt");
    }

    public static void main(String[] args) {

        OptionalTest optionalTest = new OptionalTest();

        Optional<Optional<String>> optionalNullString =    Optional.ofNullable(optionalTest.getOptionalNullString());
        if (optionalNullString.isPresent()) {

            System.out.println(optionalNullString.get());

        }

    }
}
查看更多
临风纵饮
5楼-- · 2018-12-31 06:20

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.

查看更多
春风洒进眼中
6楼-- · 2018-12-31 06:20

There are already several resources about this feature:

查看更多
回忆,回不去的记忆
7楼-- · 2018-12-31 06:22

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.

查看更多
登录 后发表回答