Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

189
Vistas
¿Por qué la inferencia de tipos de Java no distingue entre Función y Consumidor?

Dadas las siguientes funciones de identidad:

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

Observo el siguiente comportamiento en JDK 11 y 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

¿Por qué el compilador no puede resolver estos símbolos utilizando el tipo de retorno de la expresión? Las versiones de llaves funcionan bien, y hubiera pensado que serían los casos más difíciles. Entiendo que puede lanzar explícitamente la función lambda, pero eso anula el propósito de lo que estoy tratando de lograr.

over 4 years ago · Santiago Trujillo
1 Respuestas
Responde la pregunta

0

Se espera que x -> _void() y x -> one() sean compatibles con Consumer<T> (con el resultado de one() descartado).

Cuando el cuerpo lambda es de tipo bloque, el compilador comprueba adicionalmente la compatibilidad de "retorno". El JLS es bastante explícito acerca de la compatibilidad de vacío/valor para cuerpos de bloque:

Un cuerpo lambda de bloque es compatible con vacíos si cada declaración de devolución en el bloque tiene la forma de devolución; . Un cuerpo lambda de bloque es compatible con valores si no puede completarse normalmente (§14.21) y cada declaración de devolución en el bloque tiene la forma expresión de devolución; .

Si bien eso no dice por qué fallan los cuerpos de expresión única, dice exactamente por qué se compilan los cuerpos de bloque: el compilador observa los formularios de return para juzgar la compatibilidad de esos cuerpos con Consumer o Function (en este caso).

Para las expresiones de invocación de métodos, el hecho de que esto esté permitido:

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

no permite que el compilador resuelva el conflicto que observó. Puede reescribir la misma expresión lambda con cuerpos de bloque para resolver el conflicto, y eso es simplemente porque los cuerpos de bloque se verifican de manera diferente, por especificación.


Supongo que estoy tratando de decir que la pregunta más natural es "¿por qué los cuerpos de bloque se compilan en este caso" , dado que normalmente no esperamos que los tipos de retorno (¿formularios?) participen en la resolución de sobrecarga. Pero la congruencia de las expresiones lambda con los tipos es otra cosa, ¿no es así? Creo que esto (que el tipo de bloque ayuda a la inferencia de tipo objetivo) es el comportamiento especial.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda