What's the point of Guava's Optional class
Guava team member here.
Probably the single biggest disadvantage of null
is that it's not obvious what it should mean in any given context: it doesn't have an illustrative name. It's not always obvious that null
means "no value for this parameter" -- heck, as a return value, sometimes it means "error", or even "success" (!!), or simply "the correct answer is nothing". Optional
is frequently the concept you actually mean when you make a variable nullable, but not always. When it isn't, we recommend that you write your own class, similar to Optional
but with a different naming scheme, to make clear what you actually mean.
But I would say the biggest advantage of Optional
isn't in readability: the advantage 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, I 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 these reasons, we recommend that you use Optional
as a return type for your methods, but not necessarily in your method arguments.
(This is totally cribbed, by the way, from the discussion here.)
Uses for Optional
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.
Why did guava/java use possible.isPresent() as opposed to Optional.isPresent(possible)?
Because the correct way to react to the null value is by throwing a NullPointerException
, and that's what you get when you call possible.isPresent()
when possible == null
.
Java as a language allows any value of a reference type to be null
. It's up to the users of Java to not have null
values when they don't want them, and to handle them correctly when they do want them. When they fail at that, a NullPointerException
might be thrown.
Optional
is not an alternative to writing == null
. Optional
is an alternative to using null
. If you choose to not use null
, and then use null
anyway, you've created a bug.
What's the correct way to react to a programmer-introduced bug? Let's try your Optional.isPresent(value)
idea in an example:
public abstract class BaseClass {
static boolean optionalIsPresent(Optional<?> possible) {
return (possible == null) ? false : possible.isPresent();
// return possible.isPresent();
}
public final String name;
public Optional<Integer> getID();
protected BaseClass() {
if (optionalIsPresent(getID())) {
name = "number " + getID().get();
} else {
name = "nameless";
}
}
}
public class DerivedClass extends BaseClass {
private final int id;
public DerivedClass(int id) {
this.id = id;
}
public Optional<Integer> getID() {
return Optional.of(id);
}
}
There is a programmer bug here, where they are trying to use a final field before it's set.
If optionalIsPresent(null)
returns false
, then the code above executes with no errors, and we have an object with behavior different from what we thought we specified: getID()
is present, but name
is "nameless"
. We get the same result as if we had never used Optional
in the first place, and just used null and non-null values for "absent" and "present".
However, by using only absent()
to represent absent()
, our incorrect code throws a NullPointerException
.
Guava Optional. How to use the correct
Guava contributor here...
Any or all of these things are fine, but some of them may be overkill.
Generally, as discussed in this StackOverflow answer, Optional
is primarily used for two things: to make it clearer what you would've meant by null
, and in method return values to make sure the caller takes care of the "absent" case (which it's easier to forget with null
). We certainly don't advocate replacing every nullable value with an Optional
everywhere in your code -- we certainly don't do that within Guava itself!
A lot of this will have to be your decision -- there's no universal rule, it's a relatively subjective judgement, and I don't have enough context to determine what I'd do in your place -- but based on what context you've provided, I'd consider making the methods return Optional
, but probably wouldn't change any of the other fields or anything.
Java Optionals Confusion
They actually have been implemented in Java 8 so they actually haven't been "hiding" very long. But Google Guava had them for some time, and the Guava guide provides a very compelling analysis on why to use them.
https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained
Nulls suck because they are difficult to determine if they are deliberately used for a design or not. Optional forces the developer to address the idea of an absent value and check for it first.
Not to mention, the Java 8 Optional has some very powerful lambda methods, like map(), flatMap(), and filter() which streamline a chain of transformative operations on a possibly empty value without risking a null pointer exception.
There really is no good reason to use null in your designs unless you're doing some performance-intensive process. Otherwise you are just subjecting yourself to NullPointerExceptions.
Is it a good practice to use Optional as an attribute in a class?
Java 8's Optional
was mainly intended for return values from methods, and not for properties of Java classes, as described in Optional in Java SE 8:
Of course, people will do what they want. But we did have a clear intention when adding this feature, and it was not to be a general purpose
Maybe
orSome
type, as much as many people would have liked us to do so. Our intention was to provide a limited mechanism for library method return types where there needed to be a clear way to represent "no result", and usingnull
for such was overwhelmingly likely to cause errors.The key here is the focus on use as a return type. The class is definitively not intended for use as a property of a Java Bean. Witness to this is that
Optional
does not implementSerializable
, which is generally necessary for widespread use as a property of an object.
Unwrapping a Guava Optional in a single expression
It's not there because we feel the anonymous class awkwardness of writing a Closure is more awkward and less readable -- at least in Java, not necessarily in Scala -- than the local variable and the if statement that you've already written.
That said, another alternative is
for (Foo x : someExpensiveOperation().asSet()) {
// do stuff with x
}
Note that asSet
is necessary here -- Optional
very deliberately does not itself implement Iterable
.
Related Topics
Javac Not Working in Windows Command Prompt
Spring Qualifier and Property Placeholder
How to Test That No Exception Is Thrown
Are There Best Practices for (Java) Package Organization
Get Yesterday's Date Using Date
Spring @Autowired and @Qualifier
How to Resize Jlabel Imageicon
What Is the Point of the Class Option[T]
Getting the Inputstream from a Classpath Resource (Xml File)
Cannot Find Firefox Binary in Path. Make Sure Firefox Is Installed
JPA Onetomany Not Deleting Child
What Is the Most Efficient Java Collections Library
Java Singleton and Synchronization
Java - Swing Listen an Action in a Text Field of a Form
How to Pass Parameters to Anonymous Class
What Is Better: Multiple "If" Statements or One "If" with Multiple Conditions