31
public List<String> foo1() {
    List<String> retval = bar();
    if (retval == null)
        return Collections.emptyList();
    else
        return retval;
}

public List<String> foo2() {
    List<String> retval = bar();
    return retval == null ? Collections.emptyList() : retval;
}

Why does foo1() compiles fine whereas foo2() has an error? (to be more precise "Type mismatch: cannot convert from List<capture#1-of ? extends Object> to List<String>")

I would have thought that both functions would compile to the same bytecode, so a clever compiler should infer the correct type for emptyList()...

Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
Laurent Grégoire
  • 4,006
  • 29
  • 52

2 Answers2

27

Compiles for me fine in java 8.

Earlier versions of Java might need more help

return retval == null ? Collections.<String>emptyList() : retval;

should work.

EDIT This is due to improvements in Java 8 type inference as explained here

http://openjdk.java.net/jeps/101

And here's a blog with the highlights: http://blog.jooq.org/2013/11/25/a-lesser-known-java-8-feature-generalized-target-type-inference/

dkatzel
  • 31,188
  • 3
  • 63
  • 67
  • 1
    @LuiggiMendoza Java 8 improved it's type inferencing http://blog.jooq.org/2013/11/25/a-lesser-known-java-8-feature-generalized-target-type-inference/ – dkatzel Jun 18 '14 at 15:26
  • 2
    Ok, add that to your answer, otherwise looks like a long comment with some code. – Luiggi Mendoza Jun 18 '14 at 15:26
  • @lpratlong it compiles in Java 8. As I posted in my comment in OP question: which Java version are you using? – Luiggi Mendoza Jun 18 '14 at 15:27
  • @dkatzel Sorry, I'm stupid, I do not test the same thing :). Work fine: https://ideone.com/iun5CB Luiggi, no, its solution is for Java < 8. And it works, indeed. – lpratlong Jun 18 '14 at 15:29
  • I didn't knew the syntax `Foo.bar()`. Is that something new to Java 8? – Laurent Grégoire Apr 07 '15 at 15:50
  • @Laurent no, the syntax `Foo.bar()` is called "type witnessing" goes all the way back to Java 5 and is useful to help the compiler do generic typing when it can't figure it out for itself. It is valid on all method calls but is only needed if the compiler can't infer the type. The Oracle Java tutorial https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html mentions type witnessing about half way down the page – dkatzel Apr 07 '15 at 17:28
6

This is related with Type Inference from a generic method.

In case of code before ver. 8. It must be declared the type of result for this case.

return retval == null ? Collections.<String>emptyList() : retval;

Since ver. 8 notion of what is a target type has been expanded to include method arguments. So this is no longer required.

  • 1
    We do not accept link only answer. Please improve the answer or move it into a comment. Refer to [What is an acceptable answer](http://meta.stackexchange.com/a/118694/182862), section 12. – Luiggi Mendoza Jun 18 '14 at 15:25
  • 2
    Not that I am longer than you here. But there is no point of rewriting the the origin page. It is more likely not that SO will expire than oracle ;-). – Damian Leszczyński - Vash Jun 18 '14 at 15:28
  • 4
    I know lots of Oracle links in other Q/As here that expired. So, it is always better to post the explanation here than just referring to external links. These links should be to get more info to backup the answer, not the answer. – Luiggi Mendoza Jun 18 '14 at 15:30
  • Lifetime on SO means nothing. SO's rules of posting change almost by the day. – Qix - MONICA WAS MISTREATED Jun 18 '14 at 21:57