1

I tried this line while experimenting:

String test = Optional.empty().orElse("test");

--and to my surprise it gave a type error: incompatible types: Object cannot be converted to String.

Why is that? Looking at the source, orElse should just return what's being passed in if the optional is empty, which it is here. So what am I missing? This works fine, on the other hand:

String test = Optional.of("me").orElse("test");
temporary_user_name
  • 35,956
  • 47
  • 141
  • 220

2 Answers2

3

Well, this is an issue related to generics. If you look at the empty() static method, it is a generic method and has a type variable. If you just call Optional.empty then the type variable T is taken to be Object and you have incompatible types. The Optional is of type Optional<Object>, and it will dispense an Object, not a String. To fix the problem, you have to help the compiler by passing the type parameter explicitly. Here's the fix.

String test = Optional.<String> empty().orElse("test");

However, if your target type is Object, then it would work because String is some subtype of Object, as shown below.

Object test = Optional.empty().orElse("test");
temporary_user_name
  • 35,956
  • 47
  • 141
  • 220
Ravindra Ranwala
  • 20,744
  • 6
  • 45
  • 63
  • OHHH the `orElse` is using the T from `Optional.empty()` for its return type, not the T from what I pass in to `orElse`, of course not, T is already set at that point....I get it now. – temporary_user_name Feb 03 '21 at 06:24
2

Optional.empty() returns an Optional<Object>, which you then "fill" with a String. So the return type of orElse is already determined to be Object regardless of you having passed in a string as a parameter.

If you want to create an empty Optional<String> you can specify the type with:

String test = Optional.<String> empty().orElse("Test");

Alternatively, if you want automatic typing, you can do it in two steps:

Optional<String> opt = Optional.empty();
String test = opt.orElse("test");
temporary_user_name
  • 35,956
  • 47
  • 141
  • 220
assylias
  • 321,522
  • 82
  • 660
  • 783
  • What is that syntax called where you use `` in a method call like `Optional. empty()`? I haven't come across it before. I know it's part of the generics system but didn't realize it could be part of a method call in addition to a method signature or variable declaration. – temporary_user_name Feb 03 '21 at 06:27
  • 1
    @temporary_user_name I believe the `` in `Optional.empty()` is called a "type witness". – Slaw Feb 03 '21 at 06:34
  • 2
    @temporary_user_name The "official" name is defined in [JLS #15.12](https://docs.oracle.com/javase/specs/jls/se15/html/jls-15.html#jls-15.12): it's called Type Arguments. But many call it type witness. For more history, you can also read this: https://stackoverflow.com/a/32030402/829571 (and thanks for the edit). – assylias Feb 03 '21 at 17:29