Qu'est-ce que l'initialisation Double accolade en Java?


Qu'est-ce que la syntaxe d'initialisation à double accolade ({{ ... }}) en Java?

Author: Andrew Tobilko, 2009-12-24

11 answers

L'initialisation à double accolade crée une classe anonyme dérivée de la classe spécifiée (les accolades outer ) et fournit un bloc d'initialisation dans cette classe (les accolades inner ). par exemple

new ArrayList<Integer>() {{
   add(1);
   add(2);
}};

Notez qu'un effet de l'utilisation de cette initialisation à double accolade est que vous créez des classes internes anonymes. La classe créée a un pointeur implicite this vers la classe externe environnante. Bien que ce ne soit pas normalement un problème, cela peut causer du chagrin dans certaines circonstances, par exemple lors de la sérialisation ou de la collecte des ordures, et cela vaut la peine d'en être conscient.

 215
Author: Brian Agnew, 2015-06-02 09:07:45

Chaque fois que quelqu'un utilise l'initialisation double brace, un chaton est tué.

Mis à part que la syntaxe est plutôt inhabituelle et pas vraiment idiomatique (le goût est discutable, bien sûr), vous créez inutilement deux problèmes importants dans votre application, que j'ai récemment blogué plus en détail ici.

1. Vous créez beaucoup trop de classes anonymes

Chaque fois que vous utilisez l'initialisation à double accolade, une nouvelle classe est créée. E. g. cet exemple:

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");
        }});
    }});
}};

... produira ces classes:

Test$1$1$1.class
Test$1$1$2.class
Test$1$1.class
Test$1.class
Test.class

C'est un peu de frais généraux pour votre classloader-pour rien! Bien sûr, cela ne prendra pas beaucoup de temps d'initialisation si vous le faites une fois. Mais si vous le faites 20 ' 000 fois dans votre application d'entreprise... toute cette mémoire de tas juste pour un peu de"sucre de syntaxe"?

2. Vous créez potentiellement une fuite de mémoire!

Si vous prenez le code ci-dessus et retournez cette carte à partir d'une méthode, les appelants de celle-ci la méthode peut être sans méfiance s'accrocher à des ressources très lourdes qui ne peuvent pas être collectées. Prenons l'exemple suivant:

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;
    }
}

Retournés Map contient maintenant une référence à l'instance englobante de ReallyHeavyObject. Vous ne voulez probablement pas risquer cela:

Fuite De Mémoire Ici

Image de http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/

3. Vous pouvez prétendre que Java a des littéraux de carte

À répondez à votre question réelle, les gens ont utilisé cette syntaxe pour prétendre que Java a quelque chose comme des littéraux de carte, similaires aux littéraux de tableau existants:

String[] array = { "John", "Doe" };
Map map = new HashMap() {{ put("John", "Doe"); }};

Certaines personnes peuvent trouver cela syntaxiquement stimulant.

 219
Author: Lukas Eder, 2014-12-17 08:53:38
  • La première accolade crée une nouvelle Classe Interne anonyme.
  • Le deuxième ensemble d'accolades crée un initialiseur d'instance comme static block in Class.

Par exemple:

   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));
        }
    }

}

Comment cela fonctionne

First brace crée une nouvelle classe Interne anonyme. Ces classes internes sont capables d'accéder au comportement de leur classe parente. Donc, dans notre cas, nous créons en fait une sous-classe de classe HashSet, donc cette classe interne est capables d'utiliser la méthode add ().

Et Le deuxième ensemble d'accolades ne sont rien d'autre que des initialiseurs d'instance. Si vous rappelez les concepts java de base, vous pouvez facilement associer des blocs d'initialisation d'instance avec des initialiseurs statiques en raison d'une accolade similaire comme struct. La seule différence est que static initializer est ajouté avec le mot-clé static et n'est exécuté qu'une seule fois, quel que soit le nombre d'objets que vous créez.

Plus de

 35
Author: Premraj, 2018-04-17 13:01:57

Pour une application amusante de l'initialisation à double accolade, voir ici Tableau de Dwemthy en Java.

Un extrait

private static class IndustrialRaverMonkey
  extends Creature.Base {{
    life = 46;
    strength = 35;
    charisma = 91;
    weapon = 2;
  }}

private static class DwarvenAngel
  extends Creature.Base {{
    life = 540;
    strength = 6;
    charisma = 144;
    weapon = 50;
  }}

Et maintenant, préparez - vous pour le BattleOfGrottoOfSausageSmells et {gros bacon!

 21
Author: akuhn, 2009-12-24 16:57:24

Je pense qu'il est important de souligner que il n'existe pas d ' "initialisation à double accolade" en Java. Le site Web Oracle n'a pas ce terme. Dans cet exemple, deux fonctionnalités sont utilisées ensemble: la classe anonyme et le bloc d'initialisation. On dirait que l'ancien bloc d'initialisation a été oublié par les développeurs et provoque une certaine confusion dans ce sujet. Citation de Oracle docs:

Les blocs d'initialisation pour les variables d'exemple ressemblent à des blocs d'initialisation statiques, mais sans le mot-clé statique:

{
    // whatever code is needed for initialization goes here
}
 9
Author: Alex T, 2016-12-20 13:18:41

Je voudrais souligner qu'il n'existe pas d'initialisation à double accolade. Il n'y a qu'un seul bloc d'initialisation d'accolade traditionnel normal. Le deuxième bloc d'accolades n'a rien à voir avec l'initialisation. Les réponses disent que ces deux accolades initialisent quelque chose, mais ce n'est pas comme ça.

Deuxièmement, presque toutes les réponses disent que c'est une chose utilisée lors de la création de classes internes anonymes. Je pense que les gens qui lisent ces réponses auront l'impression que cela n'est utilisé que lorsque création de classes internes anonymes. Mais il est utilisé dans toutes les classes. En lisant ces réponses, il semble que ce soit un tout nouvel avenir spécial dédié aux classes anonymes et je pense que c'est trompeur.

Pour aller plus loin, cette question parle de la situation où le deuxième support d'ouverture est juste après le premier support d'ouverture. Lorsqu'il est utilisé en classe normale, il y a généralement du code entre deux accolades, mais c'est totalement la même chose. Il s'agit donc de placer entre crochets. Donc je pense que nous ne devrions pas dire que c'est une nouvelle chose passionnante, car c'est la chose que nous connaissons tous, mais juste écrite avec du code entre crochets. Nous ne devrions pas créer un nouveau concept appelé "initialisation à double accolade".

Je ne suis pas d'accord avec un argument selon lequel vous créez trop de classes anonymes. Vous ne les créez pas parce qu'un bloc d'initialisation, mais simplement parce que vous les créez. Ils seraient créés même si vous n'utilisiez pas deux accolades initialisation donc ces problèmes se produiraient même sans initialisation... L'initialisation n'est pas le facteur qui crée l'objet initialisé.

De plus, nous ne devrions pas parler de problème créé en utilisant cette chose inexistante "initialisation double accolade" ou même par initialisation normale d'un support, car les problèmes décrits n'existent qu'en raison de la création d'une classe anonyme, donc cela n'a rien à voir avec la question d'origine. Mais toutes les réponses donnent aux lecteurs l'impression que ce n'est pas la faute de créer des classes anonymes, mais ce mal chose (inexistante) appelée "initialisation double accolade".

 7
Author: ctomek, 2015-11-28 19:11:41

Pour éviter tous les effets négatifs de l'initialisation à double accolade, tels que:

  1. Compatibilité "égale" cassée.
  2. Aucune vérification effectuée, lorsque vous utilisez des affectations directes.
  3. Fuites de mémoire possibles.

Faire les choses suivantes:

  1. Créez une classe "Builder" distincte, en particulier pour l'initialisation à double accolade.
  2. Déclarer les champs avec des valeurs par défaut.
  3. Mettez la méthode de création d'objet dans cela classe.

Exemple:

public class MyClass {
    public static class Builder {
        public int    first  = -1        ;
        public double second = Double.NaN;
        public String third  = null      ;

        public MyClass create() {
            return new MyClass(first, second, third);
        }
    }

    protected final int    first ;
    protected final double second;
    protected final String third ;

    protected MyClass(
        int    first ,
        double second,
        String third
    ) {
        this.first = first ;
        this.second= second;
        this.third = third ;
    }

    public int    first () { return first ; }
    public double second() { return second; }
    public String third () { return third ; }
}

Utilisation:

MyClass my = new MyClass.Builder(){{ first = 1; third = "3"; }}.create();

Avantages:

  1. Simplement à utiliser.
  2. Ne rompt pas la compatibilité "égale".
  3. Vous pouvez effectuer des vérifications dans la méthode de création.
  4. Aucune fuite de mémoire.

Inconvénients:

  • Aucun.

Et, par conséquent, nous avons le modèle java builder le plus simple de tous les temps.

Voir tous les échantillons sur github: java-sf-builder-simple-exemple

 4
Author: Boris Podchezertsev, 2015-09-04 18:19:03

C'est - entre autres utilisations - un raccourci pour initialiser les collections. En savoir plus ...

 3
Author: miku, 2009-12-24 15:14:11

Tu veux dire quelque chose comme ça?

List<String> blah = new ArrayList<String>(){{add("asdfa");add("bbb");}};

C'est une initialisation de liste de tableau au moment de la création (hack)

 3
Author: dhblah, 2011-03-29 16:15:19

Vous pouvez mettre certaines instructions Java en boucle pour initialiser la collection:

List<Character> characters = new ArrayList<Character>() {
    {
        for (char c = 'A'; c <= 'E'; c++) add(c);
    }
};

Random rnd = new Random();

List<Integer> integers = new ArrayList<Integer>() {
    {
         while (size() < 10) add(rnd.nextInt(1_000_000));
    }
};

Mais ce cas affecte les performances, vérifiez ceci discussion

 3
Author: Anton Dozortsev, 2017-05-23 12:10:10

Cela semble être le même que le mot-clé with si populaire dans flash et vbscript. C'est une méthode pour changer ce qu'est this et rien de plus.

 0
Author: Chuck Vose, 2009-12-24 16:56:29