Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java8 generic puzzle

I'm using Java 1.8.0_151 and there is some code that doesn't compile and I don't understand:

Optional optional = Optional.of("dummy"); 
Optional<Boolean> result1 = optional.map(obj -> true);     // works fine
boolean result2 = result1.orElse(false);                   // works fine
boolean result3 = optional.map(obj -> true).orElse(false); // compilation error: Incompatible types: required boolean, found object
Object result4 = optional.map(obj -> true).orElse(false); // works fine

why it works fine on result1 but gives compilation error on result3?
Additional info:

  • In the first line, when I change Optional to Optional<String>, result3 is also able to compile
  • When I break result3 into 2 lines: like result1 and result2, result3 is able to compile
like image 324
HenryNguyen Avatar asked Nov 20 '17 12:11

HenryNguyen


2 Answers

Once you lose the type safety - it is lost for chained calls as-well. That is Optional<Object> != Optional. So when you do

 Optional optional = Optional.of("dummy");
 optional.map()

The map can only accept a raw Function and nothing else, which will return an Object obviously.

The correct way is to add type information :

Optional<String> optional = Optional.of("dummy");

Or you can cast unsafely:

boolean result3 = (boolean) optional.map(obj -> true).orElse(false)
like image 115
Eugene Avatar answered Nov 11 '22 20:11

Eugene


optional is a raw Optional, so optional.map(obj -> true) returns a raw Optional, and orElse(false) returns an Object, not a Boolean. The compiler doesn't know how to un-box an Object to boolean.

By changing

Optional optional = Optional.of("dummy"); 

to

Optional<Object> optional = Optional.of("dummy"); 

or

Optional<String> optional = Optional.of("dummy"); 

you will overcome this error, since now optional.map(obj -> true) will return an Optional<Boolean> and orElse(false) will return a Boolean.

like image 43
Eran Avatar answered Nov 11 '22 21:11

Eran