¿Cuál es el objetivo del operador diamante (<>) en Java?

Resuelto tofarr asked hace 13 años • 7 respuestas

El operador diamante en Java 7 permite código como el siguiente:

List<String> list = new LinkedList<>();

Sin embargo, en Java 5/6, puedo simplemente escribir:

List<String> list = new LinkedList();

Mi comprensión del borrado de tipos es que son exactamente iguales. (El genérico se elimina en tiempo de ejecución de todos modos).

¿Por qué molestarse con el diamante? ¿Qué nueva funcionalidad/tipo de seguridad permite? Si no ofrece ninguna funcionalidad nueva, ¿por qué la mencionan como una característica? ¿Mi comprensión de este concepto es errónea?

tofarr avatar Nov 12 '10 23:11 tofarr
Aceptado

El problema con

List<String> list = new LinkedList();

es que en el lado izquierdo, estás usando el tipo genéricoList<String> mientras que en el lado derecho estás usando el tipo sin formatoLinkedList . Los tipos sin formato en Java efectivamente solo existen por compatibilidad con código pregenérico y nunca deben usarse en código nuevo a menos que sea absolutamente necesario.

Ahora, si Java tuvo genéricos desde el principio y no tuvo tipos, como LinkedList, que se crearon originalmente antes de tener genéricos, probablemente podría haberlo hecho para que el constructor de un tipo genérico infiera automáticamente sus parámetros de tipo desde la izquierda. -lado lateral de la tarea si es posible. Pero no fue así, y debe tratar los tipos sin formato y los tipos genéricos de manera diferente para lograr compatibilidad con versiones anteriores. Eso les deja con la necesidad de crear una forma ligeramente diferente , pero igualmente conveniente, de declarar una nueva instancia de un objeto genérico sin tener que repetir sus parámetros de tipo... el operador diamante.

En cuanto a su ejemplo original de List<String> list = new LinkedList(), el compilador genera una advertencia para esa asignación porque debe hacerlo. Considera esto:

List<String> strings = ... // some list that contains some strings

// Totally legal since you used the raw type and lost all type checking!
List<Integer> integers = new LinkedList(strings);

Los genéricos existen para brindar protección en tiempo de compilación contra acciones incorrectas. En el ejemplo anterior, usar el tipo sin formato significa que no obtiene esta protección y obtendrá un error en tiempo de ejecución. Es por eso que no debes usar tipos crudos.

// Not legal since the right side is actually generic!
List<Integer> integers = new LinkedList<>(strings);

El operador diamante, sin embargo, permite que el lado derecho de la asignación se defina como una verdadera instancia genérica con los mismos parámetros de tipo que el lado izquierdo... sin tener que escribir esos parámetros nuevamente. Le permite mantener la seguridad de los genéricos con casi el mismo esfuerzo que usar el tipo crudo.

Creo que lo clave que hay que entender es que los tipos sin formato (sin <>) no pueden tratarse de la misma manera que los tipos genéricos. Cuando declara un tipo sin formato, no obtiene ninguno de los beneficios ni la verificación de tipo de los genéricos. También debes tener en cuenta que los genéricos son una parte de propósito general del lenguaje Java ... ¡no solo se aplican a los constructores sin argumentos de Collections!

ColinD avatar Nov 12 '2010 17:11 ColinD

Tu comprensión es ligeramente defectuosa. El operador de diamantes es una característica interesante ya que no es necesario repetirlo. Tiene sentido definir el tipo una vez cuando lo declaras, pero no tiene sentido definirlo nuevamente en el lado derecho. El principio SECO.

Ahora para explicar toda la confusión sobre la definición de tipos. Tiene razón en que el tipo se elimina en tiempo de ejecución, pero una vez que desea recuperar algo de una Lista con definición de tipo, lo recupera como el tipo que definió al declarar la lista; de lo contrario, perdería todas las características específicas y solo tendría las Características del objeto, excepto cuando convierte el objeto recuperado a su tipo original, lo que a veces puede ser muy complicado y dar como resultado una excepción ClassCastException.

El uso List<String> list = new LinkedList()le generará advertencias de tipo sin formato.

Octavian Helm avatar Nov 12 '2010 16:11 Octavian Helm

Esta línea provoca la advertencia [desmarcada]:

List<String> list = new LinkedList();

Entonces, la pregunta se transforma: ¿por qué la advertencia [sin marcar] no se suprime automáticamente solo en el caso de que se cree una nueva colección?

Creo que sería una tarea mucho más difícil que agregar <>funciones.

UPD : También creo que habría un desastre si se usaran legalmente tipos sin formato "sólo para algunas cosas".

Roman avatar Nov 12 '2010 16:11 Roman

En teoría, el operador diamante le permite escribir código más compacto (y legible) guardando argumentos de tipo repetido. En la práctica, son solo dos caracteres confusos más que no te dan nada. ¿Por qué?

  1. Ningún programador en su sano juicio utiliza tipos sin formato en código nuevo. Por lo tanto, el compilador podría simplemente asumir que al escribir argumentos sin tipo desea inferirlos.
  2. El operador de diamante no proporciona información de tipo, simplemente le dice al compilador: "todo estará bien". Así que al omitirlo no puedes hacer daño. En cualquier lugar donde el operador de diamantes sea legal, el compilador podría "inferirlo".

En mi humilde opinión, tener una forma clara y sencilla de marcar una fuente como Java 7 sería más útil que inventar cosas tan extrañas. En un código tan marcado, los tipos sin formato podrían prohibirse sin perder nada.

Por cierto, no creo que deba hacerse usando un modificador de compilación. La versión Java de un archivo de programa es un atributo del archivo, no hay ninguna opción. Usando algo tan trivial como

package 7 com.example;

podría dejarlo claro (es posible que prefiera algo más sofisticado que incluya una o más palabras clave sofisticadas). Incluso permitiría compilar fuentes escritas para diferentes versiones de Java juntas sin ningún problema. Permitiría introducir nuevas palabras clave (por ejemplo, "módulo") o eliminar algunas características obsoletas (múltiples clases no públicas no anidadas en un solo archivo o lo que sea) sin perder compatibilidad.

maaartinus avatar Jan 19 '2011 11:01 maaartinus