Uses for Optional

前端 未结 14 1403
眼角桃花
眼角桃花 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:26

    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());
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 01:27

    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.

    0 讨论(0)
  • 2020-11-22 01: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.

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

    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.

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

    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.

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

    The main point 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.

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