O operador de diamante no java 7 permite código como o seguinte:
List<String> list = new LinkedList<>();
No entanto, no Java 5/6, eu posso simplesmente escrever:
List<String> list = new LinkedList();
Meu entendimento do tipo apagamento é que esses são exatamente os mesmos. (O genérico é removido em tempo de execução de qualquer maneira).
Por que se preocupar com o diamante? Que nova funcionalidade / tipo de segurança ela permite? Se não gera nenhuma nova funcionalidade, por que a mencionam como um recurso? Minha compreensão desse conceito é falha?
java
generics
java-7
diamond-operator
tofarr
fonte
fonte
Respostas:
O problema com
é que, no lado esquerdo, você está usando o tipo genérico, e
List<String>
no lado direito, o tipo brutoLinkedList
. Os tipos brutos em Java efetivamente existem apenas para compatibilidade com código pré-genérico e nunca devem ser usados em novo código, a menos que você precise.Agora, se Java tivesse genéricos desde o início e não tivesse tipos, como
LinkedList
, originalmente criados antes de ter genéricos, provavelmente poderia ter feito isso para que o construtor de um tipo genérico deduza automaticamente seus parâmetros de tipo da esquerda lado da tarefa, se possível. Mas não funcionou, e deve tratar os tipos brutos e genéricos de maneira diferente para compatibilidade com versões anteriores. Isso faz com que eles precisem criar uma maneira um pouco diferente , mas igualmente conveniente, de declarar uma nova instância de um objeto genérico sem precisar repetir seus parâmetros de tipo ... o operador diamante.Quanto ao seu exemplo original
List<String> list = new LinkedList()
, o compilador gera um aviso para essa atribuição porque deve. Considere isto:Existem genéricos para fornecer proteção em tempo de compilação contra fazer a coisa errada. No exemplo acima, usar o tipo bruto significa que você não recebe essa proteção e receberá um erro no tempo de execução. É por isso que você não deve usar tipos brutos.
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 que o lado esquerdo ... sem precisar digitar esses parâmetros novamente. Permite manter a segurança dos genéricos com quase o mesmo esforço que o uso do tipo bruto.
Acho que o principal é entender que tipos brutos (sem
<>
) não podem ser tratados da mesma forma que tipos genéricos. Ao declarar um tipo bruto, você não obtém nenhum dos benefícios e a verificação de tipo de genéricos. Você também deve ter em mente que os genéricos são uma parte de uso geral da linguagem Java ... eles não se aplicam apenas aos construtores sem argumento deCollection
s!fonte
-compatibility
opção de compilação, se ausente,javac
proibirá todos os tipos brutos e aplicará apenas tipos estritamente genéricos? Isso tornará nossos códigos menos detalhados.List<String> strings = new List<>()
está OK, mas se você definirprivate List<String> my list;
e, no meio da página em que você instanciamy_list = new List<>()
, não será legal! O que minha lista contém novamente? Oh, deixe-me procurar a definição. De repente, o benefício do atalho de diamante se despede.my_list = getTheList()
:? Existem várias maneiras melhores de lidar com esse tipo de problema: 1. use um IDE que mostre tipos de variáveis ao passar o mouse. 2. use nomes de variáveis mais significativos, comoprivate List<String> strings
3. não divida a declaração e a inicialização das variáveis, a menos que você realmente precise.Sua compreensão é um pouco falha. O operador de diamante é um recurso interessante, pois você não precisa se repetir. Faz sentido definir o tipo uma vez quando você o declara, mas simplesmente não faz sentido defini-lo novamente no lado direito. O princípio DRY.
Agora, para explicar toda a confusão sobre a definição de tipos. Você está certo de que o tipo é removido no tempo de execução, mas uma vez que você deseja recuperar algo de uma Lista com definição de tipo, recupera-o como o tipo definido ao declarar a lista, caso contrário, perderia todos os recursos específicos e terá apenas o Recursos do objeto, exceto quando você converter o objeto recuperado para o tipo original, que às vezes pode ser muito complicado e resultar em uma ClassCastException.
Usando
List<String> list = new LinkedList()
você receberá avisos de tipo bruto.fonte
List<String> list = new LinkedList()
é o código correto. Você sabe disso e eu também. E a pergunta (como eu a entendo) é: por que apenas o compilador java não entende que esse código é bastante seguro?List<String> list = new LinkedList()
é o código correto. Claro, seria bom se fosse! E provavelmente poderia ter sido se o Java tivesse genéricos desde o início e não tivesse que lidar com a compatibilidade com versões anteriores de tipos genéricos que costumavam ser não genéricos, mas possui.<?>
se estiver fazendo interface com o código herdado) e o operador diamante inútil não deve existir.Esta linha causa o aviso [desmarcado]:
Portanto, a pergunta se transforma: por que o aviso [não marcado] não é suprimido automaticamente apenas no caso em que uma nova coleção é criada?
Eu acho que seria uma tarefa muito mais difícil do que adicionar um
<>
recurso.UPD : Eu também acho que haveria uma confusão se fosse legalmente usar tipos brutos 'apenas para algumas coisas'.
fonte
Em teoria, o operador diamante permite que você escreva um código mais compacto (e legível) salvando argumentos de tipo repetidos. Na prática, são apenas mais dois caracteres confusos, o que não lhe dá nada. Por quê?
IMHO, ter uma maneira clara e simples de marcar uma fonte como Java 7 seria mais útil do que inventar coisas tão estranhas. No código marcado, os tipos brutos podem ser proibidos sem perder nada.
Btw., Eu não acho que isso deve ser feito usando uma opção de compilação. A versão Java de um arquivo de programa é um atributo do arquivo, nenhuma opção. Usando algo tão trivial quanto
pode deixar claro (você pode preferir algo mais sofisticado, incluindo uma ou mais palavras-chave sofisticadas). Permitiria até compilar fontes escritas para diferentes versões Java juntas sem problemas. Isso permitiria a introdução de novas palavras-chave (por exemplo, "módulo") ou a remoção de alguns recursos obsoletos (várias classes não públicas e não aninhadas em um único arquivo ou qualquer outro) sem perder a compatibilidade.
fonte
new ArrayList(anotherList)
enew ArrayList<>(anotherList)
(especialmente se estiver sendo atribuído aList<String>
eanotherList
é aList<Integer>
)?new @RawType List()
. Essa já é uma sintaxe Java 8 válida e as anotações de tipo permitem usá-lo em todos os lugares onde for necessário, por exemplo@RawType List = (@RawType List) genericMethod();
. Considerando que os tipos brutos atualmente criam um aviso do compilador, a menos que um apropriado@SuppressWarnings
tenha sido colocado,@RawType
seria uma substituição razoável e uma sintaxe mais sutil não é necessária.Quando você escreve
List<String> list = new LinkedList();
, o compilador produz um aviso "não verificado". Você pode ignorá-lo, mas se você costumava ignorar esses avisos, também pode perder um aviso que notifica você sobre um problema de segurança real do tipo.Portanto, é melhor escrever um código que não gere avisos extras, e o operador diamante permite que você faça isso de maneira conveniente, sem repetições desnecessárias.
fonte
Tudo dito nas outras respostas é válido, mas os casos de uso não são completamente válidos para o IMHO. Se você verificar o Guava e, especialmente, o material relacionado às coleções, o mesmo será feito com os métodos estáticos. Por exemplo, Lists.newArrayList (), que permite escrever
ou com importação estática
A goiaba tem outros recursos muito poderosos como esse e, na verdade, não consigo pensar em muitos usos para o <>.
Seria mais útil se eles adotassem o comportamento do operador de diamante como padrão, ou seja, o tipo é inferido do lado esquerdo da expressão ou se o tipo do lado esquerdo fosse inferido do lado direito. O último é o que acontece em Scala.
fonte
O ponto para o operador diamante é simplesmente reduzir a digitação do código ao declarar tipos genéricos. Não tem nenhum efeito no tempo de execução.
A única diferença se você especificar no Java 5 e 6,
é que você precisa especificar
@SuppressWarnings("unchecked")
para olist
(caso contrário, receberá um aviso de elenco não verificado). Meu entendimento é que o operador de diamantes está tentando facilitar o desenvolvimento. Não tem nada a ver com a execução de genéricos em tempo de execução.fonte