Qual é o objective do operador de diamantes no Java 7?

O operador de diamante no java 7 permite um código como o seguinte:

List list = new LinkedList(); 

No entanto, no Java 5/6, posso simplesmente escrever:

 List list = new LinkedList(); 

Minha compreensão do tipo apagar é que são exatamente os mesmos. (O genérico é removido em tempo de execução).

Por que se preocupar com o diamante? Que nova funcionalidade / tipo de segurança é permitida? Se ele não produz nenhuma nova funcionalidade, por que eles mencionam isso como um recurso? Meu entendimento desse conceito é falho?

A questão com

 List list = new LinkedList(); 

é que, do lado esquerdo, você está usando o tipo genérico List no lado direito, você está usando o tipo bruto LinkedList . Os tipos brutos em Java só existem efetivamente para compatibilidade com código pré-genérico e nunca devem ser usados ​​em código novo, a menos que seja absolutamente necessário.

Agora, se Java tivesse genéricos desde o início e não tivesse tipos, como LinkedList , que foram originalmente criados antes de terem genéricos, provavelmente poderiam ter feito com que o construtor de um tipo genérico inferisse automaticamente seus parâmetros de tipo a partir do lado esquerdo da tarefa, se possível. Mas isso não aconteceu, e deve tratar tipos brutos e tipos genéricos de maneira diferente para compatibilidade com versões anteriores. Isso os deixa precisando fazer uma maneira um pouco diferente , mas igualmente conveniente, de declarar uma nova instância de um object genérico sem ter que repetir seus parâmetros de tipo … o operador de diamante.

No que diz respeito ao seu exemplo original de List list = new LinkedList() , o compilador gera um aviso para essa atribuição porque deve. Considere isto:

 List strings = ... // some list that contains some strings // Totally legal since you used the raw type and lost all type checking! List integers = new LinkedList(strings); 

Os genéricos existem para fornecer proteção em tempo de compilation contra fazer a coisa errada. No exemplo acima, usar o tipo bruto significa que você não obtém essa proteção e receberá um erro em tempo de execução. É por isso que você não deve usar tipos brutos.

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

O operador de diamante, no entanto, permite que o lado direito da atribuição seja definido como uma instância genérica verdadeira com os mesmos parâmetros de tipo do lado esquerdo … sem precisar digitar esses parâmetros novamente. Ele permite que você mantenha a segurança dos genéricos com quase o mesmo esforço que o uso do tipo bruto.

Eu acho que a chave para entender é que os tipos brutos (sem <> ) não podem ser tratados da mesma forma que os tipos genéricos. Quando você declara um tipo bruto, não recebe nenhum dos benefícios e digita a verificação de genéricos. Você também deve ter em mente que os genéricos são uma parte de propósito geral da linguagem Java … eles não se aplicam apenas aos construtores no-arg da Collection s!

Sua compreensão é um pouco falha. O operador de diamante é um ótimo recurso, já que você não precisa se repetir. Faz sentido definir o tipo uma vez quando você declara o tipo, mas não faz sentido defini-lo novamente no lado direito. O princípio DRY.

Agora, para explicar todo o fuzz sobre a definição de tipos. Você está certo que o tipo é removido em tempo de execução, mas uma vez que você deseja recuperar algo de uma Lista com definição de tipo, você o recupera como o tipo que você definiu ao declarar a lista, caso contrário perderia todos os resources específicos e teria apenas Recursos do object, exceto quando você converter o object recuperado em seu tipo original, o que às vezes pode ser muito complicado e resultar em um ClassCastException.

Usando List list = new LinkedList() você receberá avisos de rawtype.

Esta linha faz com que o aviso [desmarcado]:

 List list = new LinkedList(); 

Então, a questão transforma: por que o aviso [unchecked] não é suprimido automaticamente apenas para o caso quando uma nova coleção é criada?

Acho que seria uma tarefa muito mais difícil do que adicionar o recurso <> .

UPD : Eu também acho que haveria uma bagunça se fosse legalmente usar tipos brutos “apenas por algumas coisas”.

Em teoria, o operador de diamante permite escrever código mais compacto (e legível) salvando argumentos de tipo repetidos. Na prática, são apenas dois chars confusos que não lhe dão nada. Por quê?

  1. Nenhum programador normal usa tipos brutos em um novo código. Portanto, o compilador poderia simplesmente assumir que, ao escrever nenhum argumento de tipo, você quer que ele seja inferido.
  2. O operador de diamante não fornece informações de tipo, apenas diz o compilador, “vai ficar bem”. Então, omitindo isso, você não pode fazer mal algum. Em qualquer lugar onde o operador de diamante é legal, ele poderia ser “inferido” pelo compilador.

IMHO, ter uma maneira clara e simples de marcar uma fonte como Java 7 seria mais útil do que inventar coisas tão estranhas. Em código tão marcado, tipos brutos poderiam ser proibidos sem perder nada.

Btw., Eu não acho que isso deve ser feito usando um switch de compilation. A versão Java de um arquivo de programa é um atributo do arquivo, sem nenhuma opção. Usando algo tão trivial quanto

 package 7 com.example; 

poderia deixar claro (você pode preferir algo mais sofisticado, incluindo uma ou mais palavras-chave extravagantes). Ele permitiria até mesmo compilar fonts escritas para diferentes versões do Java sem problemas. Ele permitiria a introdução de novas palavras-chave (por exemplo, “módulo”) ou a eliminação de alguns resources obsoletos (várias classs não aninhadas não públicas em um único arquivo ou qualquer outro) sem perder qualquer compatibilidade.

Quando você escreve List list = new LinkedList(); , o compilador produz um aviso “não verificado”. Você pode ignorá-lo, mas se você costuma ignorar esses avisos, você também pode perder um aviso que avisa sobre um problema de segurança de tipo real.

Portanto, é melhor escrever um código que não gere avisos extras, e o operador de diamante permite que você o faça de maneira conveniente, sem repetições desnecessárias.

Tudo dito nas outras respostas são válidas, mas os casos de uso não são completamente válidos IMHO. Se alguém fizer check-out do Guava e especialmente do material relacionado às collections, o mesmo foi feito com methods estáticos. Por exemplo, Lists.newArrayList () que permite escrever

 List names = Lists.newArrayList(); 

ou com importação estática

 import static com.google.common.collect.Lists.*; ... List names = newArrayList(); List names = newArrayList("one", "two", "three"); 

Guava tem outros resources muito poderosos como este e eu realmente não consigo pensar em muitos usos para o <>.

Teria sido mais útil se eles fizessem o comportamento do operador de diamante como padrão, isto é, o tipo fosse inferido do lado esquerdo da expressão ou se o tipo do lado esquerdo fosse inferido do lado direito. Este último é o que acontece em Scala.

O ponto para o operador de diamante é simplesmente reduzir a digitação de código ao declarar tipos genéricos. Não tem qualquer efeito sobre o tempo de execução.

A única diferença se você especificar no Java 5 e 6,

 List list = new ArrayList(); 

é que você tem que especificar @SuppressWarnings("unchecked") para a list (caso contrário, você receberá um aviso de @SuppressWarnings("unchecked") verificado). Meu entendimento é que o operador de diamante está tentando facilitar o desenvolvimento. Não tem nada a ver com a execução de genéricos em tempo de execução.