programacion operador jdk genericos generica diamante java java-7 type-inference diamond-operator java-10

jdk - operador diamante java



Java 10: ¿La inferencia de diamantes de Java 7 funcionará con la inferencia de tipo local? (3)

"Trabajar con" es una pregunta vaga, por lo que es probable que obtenga respuestas vagas.

La inferencia de tipo no es una lectura mental; es solo resolución de restricciones. Cuantas menos restricciones de tipo haya, más probabilidades hay de que encuentre un error o un resultado sorprendente (inferir un tipo que no esperaba, como un Object ).

Diamond dice: los tipos que necesito probablemente ya estén presentes en el lado izquierdo, ¿por qué repetirlos a la derecha?

La inferencia del tipo de variable local dice: los tipos que necesito probablemente ya estén presentes en el lado derecho, por qué los repite a la izquierda.

La invocación al método genérico dice: los tipos que necesito probablemente ya estén presentes en los argumentos, por qué los repito como testigos.

Si hay suficiente información de tipo disponible en el programa sin argumentos de tipo de constructor de manifiesto o un tipo de destino a la izquierda, todo estará bien. Por ejemplo:

List<String> anotherList = ... var list = new ArrayList<>(anotherList);

Aquí, el compilador puede inferir el parámetro de tipo de ArrayList mirando el tipo de argumento al constructor (el que toma Collection<? extends E> ). Por lo tanto, infiere T=String en el RHS, y luego puede inferir ArrayList<String> en el LHS.

En otras palabras, el compilador hará todo lo posible dada la información que le haya dado. Cuanta menos información le dé, más probabilidades habrá de que falle o de que no haga lo que desea.

Dicho eso, creo que has hecho la pregunta incorrecta. La pregunta de cuánto puedes dejar de lado no debe ser impulsada por "cuánto me va a dejar el compilador", sino "cuánto daño estoy haciendo a la legibilidad de mi programa". Leer código es más importante que escribir código. Es poco probable que dejar todo lo que posiblemente pueda dejar afuera maximice la legibilidad. Debes esforzarte por irte lo suficiente para asegurarte de que ningún lector se confunda cuando te enfrentes a tu programa.

A partir del JEP 286 , vemos que podremos utilizar la inferencia de tipo local ( var ) en JDK 10 (18.3). El JEP indica que las siguientes compilaciones, que se esperan:

var list = new ArrayList<String>(); // infers ArrayList<String>

Tengo curiosidad por saber qué pasaría si intentamos lo siguiente:

var list = new ArrayList<>();

¿Incluso compilará lo que propuse en el segundo fragmento? Si es así (lo cual dudo), ¿aceptaría ArrayList Object como su tipo genérico?

Yo probaría esto por mí mismo, pero no tengo acceso a ninguna máquina en la que pueda instalar versiones anteriores.

¡Gracias!


Sí, var y el operador de diamantes se pueden combinar. El compilador inferirá el tipo genérico más específico:

var list = new ArrayList<>(); // Infers ArrayList<Object> var list = new ArrayList<>(List.of(1, 2, 3)); // Infers ArrayList<Integer>

E incluso puedes combinarlos con una clase anónima:

var list = new ArrayList<>() {};


Sí, compilaría. La var en el código

var list = new ArrayList<>();

se debe inferir como tipo ArrayList<Object> (creo que uno no puede determinar exactamente el tipo exacto del elemento debido a borrado) que sería lo mismo que utilizar un código como:

ArrayList list = new ArrayList<>(); // without the type of the element of list specified

donde la list eventualmente termina inferida como ArrayList<Object> .

De las preguntas frecuentes en la lista de correo por Brian: -

¿Qué sucede si pedimos inferencia en ambos lados?

Si usted dice:

var x = new ArrayList<>()

entonces está pidiendo que el compilador infiera tanto el argumento de tipo a List como el tipo de x .

Pero no ha proporcionado suficiente información de tipo para que el compilador haga un buen trabajo.

En la mayoría de los casos, obtendrá un error de compilación informativo que le indicará que está pidiendo que lean su mente. En algunos casos, volveremos a inferir Object , como lo hacemos actualmente con :

Object o = new ArrayList<>() // always inferred ArrayList<Object> here