3

The following segment of code issues a compiler error.

public List<Long> test()
{
    boolean b=true;
    return b ? Collections.emptyList() : Collections.emptyList();
}

incompatible types required: List<Long> found: List<Object>

It requires a generic type like,

public List<Long> test()
{
    boolean b=true;
    return b ? Collections.<Long>emptyList() : Collections.<Long>emptyList();
}

If this ternary operator is removed such as,

public List<Long> test()
{
    return Collections.emptyList();
}

or if it is represented by an if-else construct like,

public List<Long> test()
{
    boolean b=true;

    if(b)
    {
        return Collections.emptyList();
    }
    else
    {
        return Collections.emptyList();
    }        
}

then it compiles fine.

Why doesn't the first case compile? Tested on jdk-7u11.

Tiny
  • 27,221
  • 105
  • 339
  • 599

2 Answers2

4

In the case of ternary expression, compiler is not having the chance to infer the return type of the method Collections.emptyList() based on the return type of the test method. Instead, first it's having to resolve what the resulting type of the (ternary) expression would be. And since the type is not mentioned it becomes List<Object> and is incompatible with the return type of test method.

But in return Collections.emptyList(), it has the (right) context available (i.e. the return type of the test method) which it uses to infer what the return type of Collections.emptyList() should be.

Bhesh Gurung
  • 50,430
  • 22
  • 93
  • 142
1

In short, the ternary expression does not infer the type parameter from the return type, but rather from its two result expressions. Because of this nesting, the two result types must be determined before to overall result of the ternary can be determined.

The type of the ternary expression depends on the types of its operands, but one of the operands (Collections.emptyList()) has an undetermined type parameter. At that point, the ternary expression still does not have a type, so it can not influence the type parameter. There are two types to be inferred - one is the result of the ternary expression, and the other is the type parameter of the .emptyList() method.

As you found, the fix is to explicitly specify the method type for the call, by coding Collections.<Long>emptyList() to explicitly set the type, which then may be used to determine the type of the ternary expression, which in turn is checked against the return type.

Bohemian
  • 412,405
  • 93
  • 575
  • 722