Take the 2-minute tour ×

Given the generic method:

<T> List<T> getGenericList(int i) {...}

the following code compiles without any warning:

public List<String> getStringList(boolean b){
        return getGenericList(0);
        return getGenericList(1);

but this one generates 'Type mismatch' compilation error:

public List<String> getStringList(boolean b) {
    return (b) ? getGenericList(0) : getGenericList(1);


share|improve this question

5 Answers 5

up vote 7 down vote accepted

This is NOT a generics problem, but a consequence of the way the compiler has to infer the type of the ternary expression.

It happens the same with this equivalent code. This code works:

public byte function(boolean b){
        return 1;
        return 2;

While this doesn't:

public byte function(boolean b) {
    return (b) ? 1 : 2;

The reason is that when the compiler tries infer the type of this expression

    return (b) ? 1 : 2;

It first has to obtain the type of each one of the operands, and check if they are compatible (reference) to evaluate wether the ternary expression is valid or not. If the type of the "return" were propagated to automatically cast or promote each one of the operands, it could lead to resolve the type of a ternary expression differently depending on the context of this expression.

Given that the type of the "return" cannot be propagated to the operands, then in the menctioned case:


the binding of the generic type cannot be done, so the type of each one of the operands is resolved to List<Object>. Then the compiler concludes that the type of the whole expression is List<Object>, which cannot be automatically casted to List<Integer> (because they are not compatible types).

Whereas this other one

    return getGenericList(0);

It applyes the type of the "return" to bind the generic type T, so the compiler concludes that the expression has a List<String> type, that can be returned safely.

share|improve this answer
Thanks, it's quite fair explanation. Now I just wonder why compiler applies 2 different ways of processing semantically identical instructions. I mean, it could convert ternary expression into if/else form and then compile preventing ambiguity... –  Gennady Shumakher Jul 1 '11 at 1:14
Because you cannot convert automatically a ternary to an IF, because the IF requires an "statement", whereas the ternary requires a "expression". These structures are not automatically convertible one in the other. –  edutesoy Jul 1 '11 at 9:40

this is because of an edge case in generic type deduction

in the explicit returns the return type of each getGenericList can be trivially set to List (outward info propagates inwards)

but in the conditional it goes the other way the type of it is the more general of the two possibilities (inward info propagates outwards)

the compiler could deduct the info implicitly here but it's not buildin yet file a bug report if you really need it

share|improve this answer

When the trinary operator is evaluated, it's result is not bound to any type. It's as if you just call:


Try compiling the above, the compilation will fail.

In return statement, the result is bound to your function's return type and is evaluated.


I've mistaken. The above statement compiles, but the result type is evaluated as (List < Object > ). Try compiling:

List<String> l = (List<String>)getGenericList(0);

This one will fail.

share|improve this answer
+1, that's the real answer! –  Petar Minchev Jun 30 '11 at 13:13
@weekens The compilation does NOT fail with that invocation... –  edutesoy Jun 30 '11 at 13:17
@edutesoy Really! Then I must misunderstand something... –  weekens Jun 30 '11 at 13:24
@weekens, It's understood, but the question is whether it's fault of compiler or language limitation? –  Gennady Shumakher Jun 30 '11 at 13:32
I want to add: this works: return b ? this.<String> getGenericList(0) : this.<String> getGenericList(1); –  Reverend Gonzo Jun 30 '11 at 13:35

This is because javac needs to infer T, but T does not appear in argument types.

static<T> T foo(){ .. }

foo(); // T=?

Only in 2 cases, javac can infer T from the context

String s = foo(); // #1: assignment

String bar(){
    return foo(); // #2: return

In other cases, javac won't, and T is simply inferred as Object

But this type of methods are dangerous anyway. How could your method know it's time to return List<String>, not a list of something else? There's no info about T available to you.

share|improve this answer
In my case the real function is a generic JPA query executor wrapper returning a list of objects of arbitrary type. Generics was just the way to prevent compilation warnings. –  Gennady Shumakher Jul 1 '11 at 0:50
yes, the type safety is ensured by things beyond language semantics; java really can't check that. –  irreputable Jul 1 '11 at 1:15

It looks likes its just inefficient compilation.

As Maurice said, generally, the compiler determines the type of T by function arguments. In this case there aren't any.

However, because getStringList() returns List<String> and it calls return getGenericList(), the compiler is smart enough to forward the return type of getStringList to getGenericList and determine the type in that manner.

My guess is that in the ternary operator, it's doesn't bind in reverse, but rather finds the common denominator in each substatement and assigns that as the output of the ternary statement, and the compiler isn't smart enough to pass the expected output of the ternary statement into its substatements.

Note, you can directly pass the type parameter into the function call, and it works fine, ie:


compiles properly.

share|improve this answer

Your Answer


