O que é a sintaxe de inicialização do Double Brace ( {{ ... }}
) em Java?
java
initialization
double-brace-initialize
sgokhales
fonte
fonte
Respostas:
A inicialização entre chaves cria uma classe anônima derivada da classe especificada ( chaves externas ) e fornece um bloco inicializador nessa classe ( chaves internas ). por exemplo
Observe que um efeito do uso dessa inicialização entre chaves é que você está criando classes internas anônimas. A classe criada possui um
this
ponteiro implícito para a classe externa circundante. Embora normalmente não seja um problema, ele pode causar pesar em algumas circunstâncias, por exemplo, quando serializar ou coletar lixo, e vale a pena estar ciente disso.fonte
Toda vez que alguém usa a inicialização com chaves duplas, um gatinho é morto.
Além da sintaxe ser incomum e não realmente idiomática (o gosto é discutível, é claro), você está desnecessariamente criando dois problemas significativos em seu aplicativo, sobre os quais recentemente escrevi em detalhes aqui .
1. Você está criando muitas classes anônimas
Cada vez que você usa a inicialização entre chaves, uma nova classe é feita. Por exemplo, este exemplo:
... produzirá estas classes:
Isso representa um pouco de sobrecarga para o seu carregador de classe - por nada! É claro que não levará muito tempo de inicialização se você fizer isso uma vez. Mas se você fizer isso 20.000 vezes em todo o aplicativo corporativo ... toda essa memória acumulada apenas por um pouco de "açúcar de sintaxe"?
2. Você está potencialmente criando um vazamento de memória!
Se você pegar o código acima e retornar esse mapa a partir de um método, os chamadores desse método poderão estar inconscientemente segurando recursos muito pesados que não podem ser coletados com lixo. Considere o seguinte exemplo:
O retornado
Map
agora conterá uma referência à instância anexa deReallyHeavyObject
. Você provavelmente não quer arriscar que:Imagem de http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/
3. Você pode fingir que Java possui literais de mapa
Para responder à sua pergunta real, as pessoas têm usado essa sintaxe para fingir que Java tem algo como literais de mapa, semelhante aos literais de matriz existentes:
Algumas pessoas podem achar isso sintaticamente estimulante.
fonte
{{...}}
e declarado como umstatic
campo, não deve haver nenhum vazamento de memória possível, apenas uma classe anônima e nenhuma referência de instância fechada, certo?Map.of()
para o efeito, de modo que vai ser uma solução melhorReallyHeavyObject
. Além disso, as classes internas anônimas capturam todas as variáveis locais usadas no corpo da classe; portanto, se você usar não apenas constantes para inicializar coleções ou mapas com esse padrão, as instâncias da classe interna capturarão todas elas e continuarão a referenciá-las, mesmo quando realmente removidas de a coleção ou mapa. Nesse caso, essas instâncias não precisam apenas do dobro da memória necessária para as referências, mas têm outro vazamento de memória a esse respeito.Por exemplo:
Como funciona
A primeira chave cria uma nova classe interna anônima. Essas classes internas são capazes de acessar o comportamento de sua classe pai. Portanto, no nosso caso, estamos realmente criando uma subclasse da classe HashSet, portanto essa classe interna é capaz de usar o método put ().
E o segundo conjunto de chaves não passa de inicializadores de instância. Se você lembrar os conceitos principais do java, poderá associar facilmente os blocos do inicializador da instância aos inicializadores estáticos devido a chaves semelhantes a struct. A única diferença é que o inicializador estático é adicionado à palavra-chave estática e é executado apenas uma vez; não importa quantos objetos você crie.
Mais
fonte
Para uma aplicação divertida de inicialização entre chaves, veja aqui Dwemthy's Array em Java .
Um trecho
E agora, esteja preparado para o
BattleOfGrottoOfSausageSmells
e… bacon robusto!fonte
Eu acho importante enfatizar que não existe algo como "inicialização de chave dupla" em Java . O site da Oracle não possui esse termo. Neste exemplo, existem dois recursos usados juntos: classe anônima e bloco inicializador. Parece que o antigo bloco inicializador foi esquecido pelos desenvolvedores e causa alguma confusão neste tópico. Citação de documentos da Oracle :
Os blocos do inicializador, por exemplo, variáveis parecem exatamente com os blocos estáticos do inicializador, mas sem a palavra-chave estática:
fonte
1- Não existe colchetes duplos:
gostaria de salientar que não existe inicialização de colchetes duplos. Existe apenas um bloco de inicialização tradicional normal entre chaves. O segundo bloco de chaves não tem nada a ver com a inicialização. As respostas dizem que esses dois aparelhos inicializam algo, mas não é assim.
2- Não se trata apenas de classes anônimas, mas de todas as classes:
quase todas as respostas falam que isso é algo usado na criação de classes internas anônimas. Eu acho que as pessoas que lêem essas respostas terão a impressão de que isso é usado apenas ao criar classes internas anônimas. Mas é usado em todas as classes. Ler essas respostas parece um novo recurso especial dedicado a classes anônimas e acho que isso é enganoso.
3- O objetivo é colocar colchetes um após o outro, não um novo conceito:
Indo além, essa pergunta fala sobre a situação em que o segundo colchete de abertura é logo após o primeiro colchete de abertura. Quando usado na classe normal, geralmente existe algum código entre duas chaves, mas é totalmente a mesma coisa. Portanto, é uma questão de colocar colchetes. Então, acho que não devemos dizer que isso é algo novo e empolgante, porque é o que todos sabemos, mas que foi escrito com algum código entre colchetes. Não devemos criar um novo conceito chamado "inicialização entre chaves".
4- A criação de classes anônimas aninhadas não tem nada a ver com duas chaves:
não concordo com o argumento de que você cria muitas classes anônimas. Você não os está criando porque é um bloco de inicialização, mas apenas porque você os cria. Eles seriam criados mesmo se você não usasse a inicialização de dois chaves, para que esses problemas ocorressem mesmo sem a inicialização ... A inicialização não é o fator que cria objetos inicializados.
fonte
Para evitar todos os efeitos negativos da inicialização entre chaves, como:
faça as próximas coisas:
Exemplo:
Uso:
Vantagens:
Desvantagens:
E, como resultado, temos o padrão mais simples de construtor de java de todos os tempos.
Veja todos os exemplos no github: java-sf-builder-simple-example
fonte
É - entre outros usos - um atalho para inicializar coleções. Saber mais ...
fonte
você quer dizer algo assim?
é uma inicialização da lista de arrays no momento da criação (hack)
fonte
Você pode colocar algumas instruções Java como loop para inicializar a coleção:
Mas este caso afeta o desempenho, verifique esta discussão
fonte
Como apontado por @Lukas Eder, entre chaves, a inicialização de coleções deve ser evitada.
Ele cria uma classe interna anônima e, como todas as classes internas mantêm uma referência à instância pai, ela pode - e 99% provavelmente evitará - a coleta de lixo se esses objetos de coleção forem referenciados por mais objetos do que apenas o declarante.
Java 9 introduziu métodos de conveniência
List.of
,Set.of
eMap.of
, que devem ser usados em seu lugar. Eles são mais rápidos e eficientes do que o inicializador de cinta dupla.fonte
O primeiro colchete cria uma nova classe anônima e o segundo conjunto de colchetes cria inicializadores de instância como o bloco estático.
Como outros já apontaram, não é seguro usá-lo.
No entanto, você sempre pode usar esta alternativa para inicializar coleções.
fonte
Parece ser o mesmo que a palavra-chave with, tão popular no flash e no vbscript. É um método de mudar o que
this
é e nada mais.fonte
this
é. A sintaxe apenas cria uma classe anônima (portanto, qualquer referênciathis
estaria se referindo ao objeto dessa nova classe anônima) e, em seguida, usa um bloco{...}
inicializador para inicializar a instância recém-criada.