Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't optional used for instance variables?

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?

like image 336
Michael Avatar asked Jun 05 '19 08:06

Michael


3 Answers

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")
);
like image 86
Krzysztof Atłasik Avatar answered Nov 19 '22 12:11

Krzysztof Atłasik


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)
like image 36
Gal Naor Avatar answered Nov 19 '22 13:11

Gal Naor


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.

like image 3
Joop Eggen Avatar answered Nov 19 '22 13:11

Joop Eggen