Background: I recently wrote an answer where I suggested writing the following code:
Files.write(Paths.get("PostgradStudent.csv"),
        Arrays.stream(PGstudentArray).map(Object::toString).collect(Collectors.toList()),
        StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
After some thoughts, I went: "I don't actually need a list here, I just need an Iterable<? extends CharSequence>".
As Stream<T> has a method Iterator<T> iterator(), I then thought, well, that's easy:
Iterable<? extends CharSequence> iterable = () -> Arrays.stream(arr).map(Object::toString).iterator();
(I extracted it to a local variable for this question, I would like to do it inline at the end.) Unfortunately this does not compile without additional type hints:
error: incompatible types: bad return type in lambda expression
Iterable<? extends CharSequence> iterable = () -> Arrays.stream(arr).map(Object::toString).iterator();
                                                                                                   ^
    Iterator<String> cannot be converted to Iterator<CharSequence>
Of course adding some type hints will make this work:
Iterable<? extends CharSequence> iterable2 = (Iterable<String>) () -> Arrays.stream(arr).map(Object::toString).iterator();
Iterable<? extends CharSequence> iterable3 = () -> Arrays.stream(arr).<CharSequence>map(Object::toString).iterator();
In my understanding, the Java compiler does the following things:
- It looks at the target type of the expression, which is Iterable<? extends CharSequence>.
- It then determines the function type of this interface, which is () -> Iterator<? extends CharSequence>in my case.
- It then looks at the lambda and checks whether it is compatible.
In my case, the lambda has a type of () -> Iterator<String>. Which is compatible with the function type determined in step 2.
Interestingly, if I change the target of the lambda to Supplier:
Supplier<Iterator<? extends CharSequence>> supplier = () -> Arrays.stream(arr)
    .map(Object::toString)
    .iterator();
it will compile fine.
Why can't javac infer the correct type for this lambda?
 
     
     
    