¿Qué es la inicialización de Double Brace en Java?
¿ Qué es la sintaxis de inicialización de Double Brace ( {{ ... }}
) en Java?
La inicialización de doble llave crea una clase anónima derivada de la clase especificada (las llaves externas ) y proporciona un bloque inicializador dentro de esa clase (las llaves internas ). p.ej
new ArrayList<Integer>() {{
add(1);
add(2);
}};
Tenga en cuenta que un efecto de usar esta inicialización de doble llave es que está creando clases internas anónimas. La clase creada tiene un this
puntero implícito a la clase externa circundante. Aunque normalmente no es un problema, puede causar molestias en algunas circunstancias, por ejemplo, al serializar o recolectar basura, y vale la pena ser consciente de esto.
Cada vez que alguien usa la inicialización de doble llave, mata a un gatito.
Aparte de que la sintaxis es bastante inusual y no realmente idiomática (el gusto es discutible, por supuesto), estás creando innecesariamente dos problemas importantes en tu aplicación, sobre los cuales recientemente escribí con más detalle aquí .
1. Estás creando demasiadas clases anónimas
Cada vez que utiliza la inicialización de doble llave, se crea una nueva clase. Por ejemplo, este ejemplo:
Map source = new HashMap(){{
put("firstName", "John");
put("lastName", "Smith");
put("organizations", new HashMap(){{
put("0", new HashMap(){{
put("id", "1234");
}});
put("abc", new HashMap(){{
put("id", "5678");
}});
}});
}};
... producirá estas clases:
Test$1$1$1.class
Test$1$1$2.class
Test$1$1.class
Test$1.class
Test.class
Eso es una gran sobrecarga para su cargador de clases, ¡para nada! Por supuesto, no llevará mucho tiempo de inicialización si lo hace una vez. Pero si hace esto 20.000 veces en su aplicación empresarial... ¿toda esa memoria acumulada sólo por un poco de "azúcar de sintaxis"?
2. ¡Posiblemente estás creando una pérdida de memoria!
Si toma el código anterior y devuelve ese mapa desde un método, las personas que llaman a ese método podrían estar reteniendo sin sospechar recursos muy pesados que no pueden ser recolectados como basura. Considere el siguiente ejemplo:
public class ReallyHeavyObject {
// Just to illustrate...
private int[] tonsOfValues;
private Resource[] tonsOfResources;
// This method almost does nothing
public Map quickHarmlessMethod() {
Map source = new HashMap(){{
put("firstName", "John");
put("lastName", "Smith");
put("organizations", new HashMap(){{
put("0", new HashMap(){{
put("id", "1234");
}});
put("abc", new HashMap(){{
put("id", "5678");
}});
}});
}};
return source;
}
}
El archivo devuelto Map
ahora contendrá una referencia a la instancia adjunta de ReallyHeavyObject
. Probablemente no quieras arriesgarte a eso:
Imagen de http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/
3. Puedes fingir que Java tiene mapas literales.
Para responder a su pregunta real, la gente ha estado usando esta sintaxis para pretender que Java tiene algo así como literales de mapa, similares a los literales de matriz existentes:
String[] array = { "John", "Doe" };
Map map = new HashMap() {{ put("John", "Doe"); }};
Algunas personas pueden encontrar esto estimulante sintácticamente.
- La primera llave crea una nueva clase interna anónima.
- El segundo conjunto de llaves crea inicializadores de instancia como un bloque estático en Clase.
Por ejemplo:
public class TestHashMap {
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<String,String>(){
{
put("1", "ONE");
}{
put("2", "TWO");
}{
put("3", "THREE");
}
};
Set<String> keySet = map.keySet();
for (String string : keySet) {
System.out.println(string+" ->"+map.get(string));
}
}
}
Cómo funciona
La primera llave crea una nueva clase interna anónima. Estas clases internas son capaces de acceder al comportamiento de su clase principal. Entonces, en nuestro caso, en realidad estamos creando una subclase de la clase HashSet, por lo que esta clase interna es capaz de usar el método put().
Y el segundo conjunto de llaves no son más que inicializadores de instancia. Si recuerda los conceptos básicos de Java, puede asociar fácilmente bloques de inicializador de instancia con inicializadores estáticos debido a una estructura similar a una llave. La única diferencia es que el inicializador estático se agrega con la palabra clave estática y se ejecuta solo una vez; no importa cuántos objetos crees.
más