16

I was playing with the following question: Using Java 8's Optional with Stream::flatMap and wanted to add a method to a custom Optional<T> and then check if it worked.
More precise, I wanted to add a stream() to my CustomOptional<T> that returns an empty stream if no value is present, or a stream with a single element if it is present.

However, I came to the conclusion that Optional<T> is declared as final.

Why is this so? There are loads of classes that are not declared as final, and I personally do not see a reason here to declare Optional<T> final.

As a second question, why can not all methods be final, if the worry is that they would be overridden, and leave the class non-final?

Neuron
  • 5,141
  • 5
  • 38
  • 59
skiwi
  • 66,971
  • 31
  • 131
  • 216

4 Answers4

18

According to this page of the Java SE 8 API docs, Optional<T> is a value based class. According to this page of the API docs, value-based classes have to be immutable.

Declaring all the methods in Optional<T> as final will prevent the methods from being overridden, but that will not prevent an extending class from adding fields and methods. Extending the class and adding a field together with a method that changes the value of that field would make that subclass mutable and hence would allow the creation of a mutable Optional<T>. The following is an example of such a subclass that could be created if Optional<T> would not be declared final.

//Example created by @assylias
public class Sub<T> extends Optional<T> {
    private T t;

    public void set(T t) {
        this.t = t;
    }
}

Declaring Optional<T> final prevents the creation of subclasses like the one above and hence guarantees Optional<T> to be always immutable.

SharpKnight
  • 455
  • 2
  • 14
  • 1
    So, because somebody _might_ override the class to make it mutable the spec wont allow subclasses? The reason this annoys me is because I'd like to replace exception-flow with optional-flow, such that rather than return a value or throw an exception, we could only return an optional and append the exception to it in the error flow, maybe requiring the addition of `ifError(Consumer consumer)` and `getCause()` methods. Seems to me this is a good use of traditional inheritence: extending --but not invalidating-- the original behavior. Bummer I cant do it. – Groostav May 20 '15 at 00:24
  • To me, it would still be immutable with regard to the original state. The case that @Groostav made is exactly the case I also have and it seems like a perfectly valid case to me. It follows the contract imposed by Optional and it is transparent to existing usages of the optional in a way that composition or Exceptions cannot be. – neXus Mar 24 '17 at 11:26
  • @neXus, since writing that comment I've switched to kotlin (kotlinlang.org) and have used one of their many solutions to this problem. Between `Pair`s (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/) and `Either`'s, this is a solved problem... well for everybody on the JVM except java. – Groostav Mar 25 '17 at 18:39
3

As others have stated Optional is a value based class and since it is a value based class it should be immutable which needs it to be final.

But we missed the point for this. One of the main reason why value based classes are immutable is to guarantee thread safety. Making it immutable makes it thread safe. Take for eg String or primitive wrappers like Integer or Float. They are declared final for similar reasons.

Aniket Thakur
  • 66,731
  • 38
  • 279
  • 289
1

Probably, the reason is the same as why String is final; that is, so that all users of the Optional class can be assured that the methods on the instance they receive keep to their contract of always returning the same value.

Dolda2000
  • 25,216
  • 4
  • 51
  • 92
  • 1
    This would still be possible if all the methods were `final` and the class itself was non-final, unless I am mistaken? – skiwi Mar 29 '14 at 18:04
  • Admittedly so, but the same thing could be said for `String`. Java has a tendency to be a bit fascist to protect you from doing the Wrong Thing. ;) – Dolda2000 Mar 29 '14 at 18:08
1

Though we could not extend the Optional class, we could create our own wrapper class.

public final class Opt {

    private Opt() {

    }

    public static final <T> Stream<T> filledOrEmpty(T t) {

        return Optional.ofNullable(t).isPresent() ? Stream.of(t) : Stream.empty();

    }

}

Hope it might helps you. Glad to see the reaction!

Prakash Ayappan
  • 455
  • 2
  • 8