Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

186
Visualizações
Why does Java type inference fail to distinguish between Function and Consumer?

Given the following identity functions:

<T> Consumer<T> f(Consumer<T> c) { return c; }          // (1)
<T,R> Function<T,R> f(Function<T, R> c) { return c; }   // (2)

I observe the following behaviour in JDK 11 and JDK 17:

void _void() {}
f(x -> {});                   // okay, dispatches to (1)
f(x -> { return; });          // okay, dispatches to (1)
f(x -> { _void(); });         // okay, dispatches to (1)
f(x -> _void());              // should dispatch to (1)
|  Error:
|  reference to f is ambiguous
|    both method f(java.util.function.Function<java.lang.Object,java.lang.Object>) in  
     and method f(java.util.function.Consumer<java.lang.Object>) in  match

int _one() { return 1; }
f(x -> 1);                    // okay, dispatches to (2)
f(x -> { return 1; });        // okay, dispatches to (2)
f(x -> { return _one(); });   // okay, dispatches to (2)
f(x -> _one());               // should dispatch to (2)
|  Error:
|  reference to f is ambiguous
|    both method <T,R>f(java.util.function.Function<T,R>) in
     and method <T>f(java.util.function.Consumer<T>) in  match

Why can't the compiler resolve these symbols by using the return type of the expression? The curly brace versions work fine, and I would have thought they would be the more difficult cases. I understand that you can explicity cast the lambda function, but that defeats the purpose of what I am trying to achieve.

over 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

x -> _void() and x -> one() are expected to be compatible with Consumer<T> (with the result of one() to be discarded).

When the lambda body is of a block type, the compiler additionally checks the "return" compatibility. The JLS is rather explicit about void/value compatibility for block bodies:

A block lambda body is void-compatible if every return statement in the block has the form return;. A block lambda body is value-compatible if it cannot complete normally (§14.21) and every return statement in the block has the form return Expression;.

While that doesn't say why the single-expression bodies fail, it says exactly why block bodies compile: the compiler looks at the return forms to judge on those bodies' compatibility with Consumer or Function (in this case).

For the method invocation expressions, the fact that this is allowed:

Consumer<Integer> c = x -> one(); //discarded result
Function<T, Integer> f = x -> one(); //returned result

doesn't enable the compiler to resolve the conflict that you observed. You can rewrite the same lambda expression with block bodies to resolve the conflict, and that's simply because block bodies are checked differently, by spec.


I guess I'm trying to say that the more natural question is "why block bodies compile at all in this case", given that we normally don't expect return types (forms?) to participate in overload resolution. But lambda expressions' congruence with types is something else, isn't it... I think this (that block type helps target type inference) is the special behavior.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda