I would not attempt to explain why the current version of IntelliJ doesn't issue a warning for a record having optional fields (that's a question for developers of the IDE).
In this post, I'm addressing the question regarding recommended practices of using Optional
, in particular with Java 16 Records.
Does the practice of not using Optional<T>
types as parameters/fields not apply to record parameters
Firstly, Optional
is not intended to be used as a field type, for that reason Optional
doesn't implement Serializable
(see). Secondly, records are data-carriers, their fields are final
. Hence, if a record gets initialized with optionals that are empty, they would stay empty throughout all its time-span.
Usage of Optional
Here's a quote from the answer by @StuartMarks, Java and OpenJDK developer, regarding what Optional
is meant to be used for:
The primary use of Optional
is as follows:
Optional is intended to
provide a limited mechanism for library method return types where
there is a clear need to represent "no result," and where using null
for that is overwhelmingly likely to cause errors.
The only valid usage for Optional is returning it from a method where it was originated. And the caller should immediately unpack the optional (API offers plenty of methods for that). But if you're passing the optional object around and storing it somewhere, then what you're doing isn't a good practice.
Optional is not meant for
Optional is not meant to be used:
- As a field type;
- As a type of the method parameter;
- To be stored in a
Collection
;
- Or utilized to perform null-checks. Substituting explicit null-check with
Optional.ofNullable()
is an antipattern.
Here's a quote from the answer by @Brian Goetz, Java Language Architect
(Should Java 8 getters return optional type?):
Of course, people will do what they want...
For example, you probably should never use it for something that
returns an array of results, or a list of results; instead return an
empty array or list. You should almost never use it as a field
of something or a method parameter.
Also, have a look at this answer by StuartMarks, here's a small quote:
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.
Records are Transparent carriers for Immutable data
An object with Optional fields forces the one who deals with it always take into consideration that the object obtained via a getter isn't a value, but potentially empty optional, which might throw NoSuchElementException
if you blindly invoke get()
on it.
Also, having fields of Optional type in a Record is in contradiction with the general concept of Records.
Here's a definition of Record from the JEP 395:
records, which are classes that act as transparent carriers for immutable data. Records can be thought of as nominal tuples.
A record with Optional fields is no longer transparent, because we're not able to get a value directly from it via accessor method.
Since record fields are immutable, it doesn't make sense to store potentially empty optionals as record properties, it almost the same as storing null-references. Because fields in a record can't be changed, an empty optional will remain empty, and some of your tuples might not contain useful data at all.
There's no advantage in passing around optionals, storing them inside records in order to find out at a later point in time that they don't contain the actual data.
Instead, you have to extract a value (if present) from an Optional object obtained from somewhere right on the spot before creating a record.