I've been reading up a lot about the cases where Optional
should be used.
A lot of the pages I've read say that Optional
shouldn't be used for private instance variables and instead should be returned by getters.
I would have thought that having private instance variables as optional would still be useful. If anybody looks at my code they can see that a value can be empty, instead of having to check the documentation to see if null could be returned.
In Scala null is never used and is only really there for interoperability with Java. It is recommended to always use an optional if a value can be null. This approach makes a lot more sense to me.
Here's a page mentioning it:
https://blog.joda.org/2015/08/java-se-8-optional-pragmatic-approach.html
Here is the example code.
private final String addressLine; // never null
private final String city; // never null
private final String postcode; // optional, thus may be null
// normal getters
public String getAddressLine() { return addressLine; }
public String getCity() { return city; }
// special getter for optional field
public Optional<String> getPostcode() {
return Optional.ofNullable(postcode);
}
The only advantage I can see is that if you want to serialize the object it is now possible as it isn't storing optional in a variable.
The disadvantage is that you don't know postcode could be null until you check the return type of the getter. If you were new to the code you might miss this add extend the class, causing a null pointer exception.
Here is a question asked about Scala's Option
.
When to use Option
Why is there a difference between Java and Scala with how optional should be used?
Not all Java developers even agree with the approach you described. Please check this post by the creator of Lombok.
I guess that the reason for a different approach of using Optional
in Java is that Java's community lived without it up till Java 8, so most people were used to null. In one hand a lot of new APIs (like findAny
from Stream
) return Optional
, but still a lot of standard library methods just return null, so you always have to remember either to wrap your function calls with Optional.ofNullable
or check if the value is not null.
Optional
was added to Java 8 but it is discouraged to use it as class fields because Optional
is not implementing Serializable
(and Java's serialization is used as the default serialization engine by many frameworks or systems like Akka, Spark, Kafka, etc.).
On the other hand Option
is very tightly bound with the Scala standard library.
As far as I know, no Scala's standard library APIs return null, but Option
, and it is discouraged to use null at all in your Scala code. You can even configure your project that it will fail to compile if null is used.
Option
is also Serializable
and its normal practice to use is as class fields for values that can be empty.
If you want to use a similar approach in your Java code please check Option from Vavr. It's serializable, so it can be safely used as fields and it also has two subclasses None
and Some
(similarly as Scala's Option
), so it can be used in Vavr's pattern matching:
Match(option).of(
Case($Some($()), "defined"),
Case($None(), "empty")
);
In Scala, Option is tightly integrated into the language's API.
Represents optional values. Instances of Option are either an instance of scala.Some or the object None. The most idiomatic way to use an scala.Option instance is to treat it as a collection or monad and use map,flatMap, filter, or foreach.
As you can see from the quote above, there is no null
explanation there, because it should be used as a monad or as a collection.
In Java, Optional is used to save us from NullPointerException cases, by using it as:
A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.
A programming language that shows the user very clearly if the variable can be null or not is Kotlin, by using ? safe call, and shows you compilation errors:
var a: String = "abc"
a = null // compilation error
var b: String? = "abc"
b = null // ok
print(b)
There is the position, that Optional, like Stream, is an iterating «event» class, not deserving to be used as field in a "real" object.
Then there is the short-coming of not being Serializable (which one may work around).
However my opinion is that some variables may be optional, of cardinality 0 and 1.
Just as a list is valid too. With List
fields the trend is (IMHO) that it is not let to be null initially, but to always have an (empty) list.
In the same coding style, an Optional
ensures that only safe access is used, and especially one may map in a chaining style:
Optional<TextField> t = ...
String s = t.map(t::getText).orElse("N/A");
Optional<String> u = t.map(t::getText);
t.ifPresent(s -> { ... });
Especially the ifPresent
ensures not working with null unintendedly.
Optional is a valuable specification.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With