Uses for Optional

前端 未结 14 1404
眼角桃花
眼角桃花 2020-11-22 01:01

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 se

相关标签:
14条回答
  • 2020-11-22 01:35

    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)

    0 讨论(0)
  • 2020-11-22 01:35

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

    0 讨论(0)
提交回复
热议问题