Účinnost Java "Double Brace Inicializace"?

hlasů
669

V skryté funkce Javy horní odpověď zmiňuje Double Brace inicializace , s velmi lákavou syntaxe:

Set<String> flavors = new HashSet<String>() {{
    add(vanilla);
    add(strawberry);
    add(chocolate);
    add(butter pecan);
}};

Tento idiom vytváří anonymní vnitřní třídu jen instanci inicializátoru v něm, který „lze použít jakékoliv [...] metody v obsahujícím rozsahu“.

Hlavní otázka: Je to jako neefektivní , jak to vypadá? By mělo být jeho použití omezeno na jednorázové inicializace? (A samozřejmě předvádět!)

Druhá otázka: Nová HashSet musí být „to“ použitý v instanci inicializátor ... někdo může vrhnout světlo na mechanismus?

Třetí otázka: Je to idiom příliš temný používat ve výrobním kódem?

Shrnutí: Velmi, velmi pěkné odpovědi, díky všem. Na otázku (3), lidé cítili syntaxe by měla být jasná (i když bych doporučil občas příspěvky, a to zejména, pokud váš kód předá vývojářům, kteří nemusí být obeznámeni s tím).

Na otázku (1), vygenerovaný kód by měl běžet rychle. Extra .class soubory dělat příčina jar soubor nepořádek a pomalé spouštění programu mírně (díky @coobird pro měření to). @Thilo poukázal na to, že sběr odpadu může být ovlivněna, a paměť náklady na dodatečné načtených tříd mohou být faktorem v některých případech.

Otázka (2) Ukázalo se, že nejzajímavější pro mě. Pokud chápu odpovědi, co se děje v DBI je, že anonymní vnitřní třída rozšiřuje třídu objektu buduje nový operátor, a proto má „to“ hodnotu odkazující na instanci buduje. Velmi elegantní.

Celkově lze říci, DBI mi připadá jako něco intelektuální zvědavosti. Coobird a jiní poukazují můžete dosáhnout stejného efektu s Arrays.asList, varargs metody, kolekce Google a navrhované Java 7 Sběr literály. Novější JVM jazyků, jako je Scala, JRuby a Groovy také nabízejí stručné zápisy na seznam výstavbu a dobře spolupracovat s Javou. Vzhledem k tomu, že DBI cluttery up cesty tříd, zpomaluje třídy zatížení trochu, a dělá kód tad více temný, asi bych se vyhýbat od něj. Nicméně, mám v plánu na jaře to na kamaráda, který se právě dostali svůj SCJP a miluje dobromyslný klání o Java sémantice! ;-) Děkuji všem!

7/2017: Baeldung má dobrý přehled o inicializaci dvojité vzpěry a domnívá se, že anti-vzor.

12/2017: @Basil Bourque konstatuje, že v novém jazyce Java 9 můžete říci:

Set<String> flavors = Set.of(vanilla, strawberry, chocolate, butter pecan);

To je jistě správná cesta. Pokud jste přilepená s dřívější verzí, se podívat na ImmutableSet Google sbírek .

Položena 29/05/2009 v 04:40
zdroj uživatelem
V jiných jazycích...                            


15 odpovědí

hlasů
515

Tady je ten problém, když jsem se příliš unést s anonymním vnitřních tříd:

2009/05/27  16:35             1,602 DemoApp2$1.class
2009/05/27  16:35             1,976 DemoApp2$10.class
2009/05/27  16:35             1,919 DemoApp2$11.class
2009/05/27  16:35             2,404 DemoApp2$12.class
2009/05/27  16:35             1,197 DemoApp2$13.class

/* snip */

2009/05/27  16:35             1,953 DemoApp2$30.class
2009/05/27  16:35             1,910 DemoApp2$31.class
2009/05/27  16:35             2,007 DemoApp2$32.class
2009/05/27  16:35               926 DemoApp2$33$1$1.class
2009/05/27  16:35             4,104 DemoApp2$33$1.class
2009/05/27  16:35             2,849 DemoApp2$33.class
2009/05/27  16:35               926 DemoApp2$34$1$1.class
2009/05/27  16:35             4,234 DemoApp2$34$1.class
2009/05/27  16:35             2,849 DemoApp2$34.class

/* snip */

2009/05/27  16:35               614 DemoApp2$40.class
2009/05/27  16:35             2,344 DemoApp2$5.class
2009/05/27  16:35             1,551 DemoApp2$6.class
2009/05/27  16:35             1,604 DemoApp2$7.class
2009/05/27  16:35             1,809 DemoApp2$8.class
2009/05/27  16:35             2,022 DemoApp2$9.class

Jsou to všechny třídy, které byly generovány, když jsem dělal jednoduchou aplikaci a použité velkého množství anonymních vnitřních tříd - každá třída být sestaveny do samostatného classsouboru.

Dále jen „inicializace dvojitá vzpěra“, jak již bylo uvedeno, je anonymní vnitřní třídou instance inicializace bloku, což znamená, že nová třída je vytvořena pro každý „inicializaci“, to vše za účelem obvykle aby jeden objekt.

Vzhledem k tomu, že Java Virtual Machine bude muset číst všechny ty tříd při jejich použití, které mohou vést k určitému času v bytecode ověření při zpracování a podobně. Nemluvě o zvýšení potřebného místa na disku, s cílem ukládat všechny tyto classsoubory.

Zdá se, jako kdyby tam je trochu nad hlavou, když s využitím inicializace dvojité rovnátka, takže to asi není tak dobrý nápad jít příliš přehánět s ním. Ale jak Eddie zaznamenala v komentářích, že to není možné být absolutně jisti nárazu.


Jen pro referenci inicializace double ortéza je následující:

List<String> list = new ArrayList<String>() {{
    add("Hello");
    add("World!");
}};

Vypadá to, že „skryté“ funkce Java, ale je to jen přepis:

List<String> list = new ArrayList<String>() {

    // Instance initialization block
    {
        add("Hello");
        add("World!");
    }
};

Takže je to v podstatě instance inicializace bloku , který je součástí anonymní vnitřní třídy .


Joshua Bloch je návrh Collection Literály k projektu Coin byl v duchu:

List<Integer> intList = [1, 2, 3, 4];

Set<String> strSet = {"Apple", "Banana", "Cactus"};

Map<String, Integer> truthMap = { "answer" : 42 };

Je smutné, že to nedělal svou cestu do ani Javě 7 ani 8 a byl odložen na neurčito.


Experiment

Tady je jednoduchý experiment Testoval jsem - že vznikne 1000 ArrayListů s prvky "Hello"a "World!"přidal k nim pomocí addmetody, pomocí dvou metod:

Metoda 1: Double Brace Inicializace

List<String> l = new ArrayList<String>() {{
  add("Hello");
  add("World!");
}};

Metoda 2: konkretizovat ArrayListaadd

List<String> l = new ArrayList<String>();
l.add("Hello");
l.add("World!");

Vytvořil jsem jednoduchý program vypsat zdrojový soubor Java provést 1000 inicializace pomocí dvou metod:

Test 1:

class Test1 {
  public static void main(String[] s) {
    long st = System.currentTimeMillis();

    List<String> l0 = new ArrayList<String>() {{
      add("Hello");
      add("World!");
    }};

    List<String> l1 = new ArrayList<String>() {{
      add("Hello");
      add("World!");
    }};

    /* snip */

    List<String> l999 = new ArrayList<String>() {{
      add("Hello");
      add("World!");
    }};

    System.out.println(System.currentTimeMillis() - st);
  }
}

Test 2:

class Test2 {
  public static void main(String[] s) {
    long st = System.currentTimeMillis();

    List<String> l0 = new ArrayList<String>();
    l0.add("Hello");
    l0.add("World!");

    List<String> l1 = new ArrayList<String>();
    l1.add("Hello");
    l1.add("World!");

    /* snip */

    List<String> l999 = new ArrayList<String>();
    l999.add("Hello");
    l999.add("World!");

    System.out.println(System.currentTimeMillis() - st);
  }
}

Vezměte prosím na vědomí, že uplynulá doba inicializovat 1000 ArrayListS a 1000 anonymní vnitřní třídy rozšiřující ArrayListse kontroluje s System.currentTimeMillis, takže časovač nemá velmi vysoké rozlišení. Na mém systému Windows, rozlišení se pohybuje kolem 15 až 16 milisekund.

Výsledky pro 10 pokusů ze dvou testů byly následující:

Test1 Times (ms)           Test2 Times (ms)
----------------           ----------------
           187                          0
           203                          0
           203                          0
           188                          0
           188                          0
           187                          0
           203                          0
           188                          0
           188                          0
           203                          0

Jak lze vidět, inicializační dvojitá výztuha má znatelný čas spuštění okolo 190 ms.

Mezitím, ArrayListdoba provedení inicializace vyšel jako 0 ms. Samozřejmě, že je rozlišení časovače je třeba vzít v úvahu, ale je pravděpodobné, že být delší než 15 ms.

Takže se zdá, že znatelný rozdíl v době provádění těchto dvou metod. Se zdá, že skutečně existuje nějaký režie ve dvou inicializace metody.

A ano, tam bylo 1000 .classSoubory generované sestavování Test1dvojité rovnátka inicializační testovací program.

Odpovězeno 29/05/2009 v 04:59
zdroj uživatelem

hlasů
88

Jedna vlastnost tohoto přístupu, který nebyl poukázal tak daleko, že proto, že jste vytvářet vnitřní třídy, je třída obsahující celek je zachycen ve své působnosti. To znamená, že pokud vaše Set je stále naživu, bude to udržet ukazatel, který obsahuje instance ( this$0) a držet to od bytí garbage collector, který by mohl být problém.

Toto, a skutečnost, že nová třída dostane vytvořené na prvním místě, i když pravidelný HashSet bude fungovat stejně dobře (nebo dokonce lepší), se mi nebude chtít použít tento konstrukt (i když jsem opravdu touží po syntaktický cukr).

Druhá otázka: Nová HashSet musí být „to“ použitý v instanci inicializátor ... někdo může vrhnout světlo na mechanismus? Byl bych naivní očekávat, „to“ se odkazovat na objekt inicializace „chuť“.

To je to, jak vnitřní třídy fungovat. Dostanou svou vlastní this, ale mají také odkazy na nadřazené instance, takže můžete volat metody objektu, který obsahuje stejně. V případě konfliktu názvů, vnitřní třídy (ve vašem případě HashSet) má přednost, ale můžete prefix „to“ s newClassName získat vnější metodu stejně.

public class Test {

    public void add(Object o) {
    }

    public Set<String> makeSet() {
        return new HashSet<String>() {
            {
              add("hello"); // HashSet
              Test.this.add("hello"); // outer instance 
            }
        };
    }
}

Aby bylo jasné, na vznikají anonymní podtřídy, můžete definovat metody i tam. Například přepsáníHashSet.add()

    public Set<String> makeSet() {
        return new HashSet<String>() {
            {
              add("hello"); // not HashSet anymore ...
            }

            @Override
            boolean add(String s){

            }

        };
    }
Odpovězeno 29/05/2009 v 06:37
zdroj uživatelem

hlasů
34

Vezmeme-li následující zkušební třída:

public class Test {
  public void test() {
    Set<String> flavors = new HashSet<String>() {{
        add("vanilla");
        add("strawberry");
        add("chocolate");
        add("butter pecan");
    }};
  }
}

a pak dekompilace souboru třídy, vidím:

public class Test {
  public void test() {
    java.util.Set flavors = new HashSet() {

      final Test this$0;

      {
        this$0 = Test.this;
        super();
        add("vanilla");
        add("strawberry");
        add("chocolate");
        add("butter pecan");
      }
    };
  }
}

To nevypadá hrozně neefektivní ke mně. Pokud bych měl obavy o výkon pro něco takového, tak bych ho profilu. A vaše otázka č.2 je zodpovězena výše uvedený kód: Jsi uvnitř implicitního konstruktoru (a například inicializátor) na své vnitřní třídy, aby „ this“ se vztahuje k této vnitřní třídy.

Ano, tato syntaxe je temný, ale komentář může objasnit nejasné využití syntaxe. K objasnění syntaxe, většina lidí jsou obeznámeni s statickou inicializátor bloku (JLS 8,7 Static Inicializátory):

public class Sample1 {
    private static final String someVar;
    static {
        String temp = null;
        ..... // block of code setting temp
        someVar = temp;
    }
}

Můžete také použít podobnou syntaxi (bez slova " static„) pro použití konstruktoru (JLS 8.6 Instance Inicializátory), i když jsem nikdy neviděl to používá ve výrobním kódem. To je mnohem méně běžně známé.

public class Sample2 {
    private final String someVar;

    // This is an instance initializer
    {
        String temp = null;
        ..... // block of code setting temp
        someVar = temp;
    }
}

Pokud nechcete mít výchozí konstruktor, pak blok kódu mezi {a }je otočen do konstruktoru kompilátorem. S ohledem na tuto skutečnost odhalit dvojitý kód rovnátka:

public void test() {
  Set<String> flavors = new HashSet<String>() {
      {
        add("vanilla");
        add("strawberry");
        add("chocolate");
        add("butter pecan");
      }
  };
}

Blok kódu mezi vnitřními-většina výztuh je otočen do konstruktoru kompilátorem. Vnější-nejvíce závorky ohraničují anonymní vnitřní třídy. Chcete-li mít tento konečný krok učinit vše non-anonymous:

public void test() {
  Set<String> flavors = new MyHashSet();
}

class MyHashSet extends HashSet<String>() {
    public MyHashSet() {
        add("vanilla");
        add("strawberry");
        add("chocolate");
        add("butter pecan");
    }
}

Za účelem inicializace, řekl bych, že není nad hlavou vůbec (nebo tak malý, že lze zanedbat). Nicméně, každý využití flavorspůjde nebráním HashSetale proti MyHashSet. Tam je pravděpodobně malý (a dost možná zanedbatelné) nad hlavou, jak to. Ale na druhou stranu, než jsem strach o tom, bych to profil.

Opět platí, že na vaši otázku # 2, výše uvedený kód je logické a explicitní ekvivalent inicializace dvojité vzpěry, a to je zřejmé, kde „ this“ se rozumí: Pro vnitřní třídy, která rozšiřuje HashSet.

Máte-li dotazy týkající se podrobností o stupni Inicializátory, podívejte se na podrobnosti v JLS dokumentaci.

Odpovězeno 29/05/2009 v 04:52
zdroj uživatelem

hlasů
31

Pokaždé, když někdo používá dvojité rovnátka inicializace kotě zabit.

Na rozdíl od syntaxe je poněkud neobvyklá a není opravdu idiomatickou (chuť, je diskutabilní, samozřejmě), se zbytečně vytváří dvě významné problémy v aplikaci, která jsem nedávno blogged o podrobněji zde .

1. Ty vytváří příliš mnoho anonymních tříd

Pokaždé, když pomocí dvojité rovnátka inicializaci nová třída je vyroben. Například tento příklad:

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

... bude vyrábět tyto třídy:

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

To je docela dost režii za svůj ClassLoader - pro nic za nic! Samozřejmě, že to nebude trvat dlouho inicializace, pokud si to jednou. Ale pokud to budete dělat 20'000-krát v celém svém podnikové aplikace ... všechny ty haldy paměti jen pro trochu „syntaxe cukru“?

2. Ty potenciálně vytvořit nevracení paměti!

Pokud budete mít výše uvedený kód a tuto mapu návratu z metody, volající o této metodě může být unsuspectingly drží na velmi těžkých zdroje, které nemůže být uvolněna. Vezměme si následující příklad:

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

Vrácený Mapbude nyní obsahovat odkaz na vkládací instanci ReallyHeavyObject. Pravděpodobně nebudete chtít riskovat, že:

Memory Leak Right Here

Snímek ze http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/

3. Můžete předstírat, že Java má mapové literály

Chcete-li odpovědět na vaši skutečnou otázku, lidé byli pomocí této syntaxe předstírat, že Java má něco jako mapových literály, podobné stávajícím pole konstantě

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

Někteří lidé mohou najít to syntakticky stimulující.

Odpovězeno 17/12/2014 v 08:56
zdroj uživatelem

hlasů
31

úniku náchylný

. Rozhodl jsem se přizvukovat Dopad výkonnosti zahrnuje: Operace disk + unzip (pro sklenice), verifikace class, perm-gen prostor (pro Sun Hotspot JVM). Nicméně nejhorší ze všeho: je to unikat náchylné. Nemůžete jednoduše vrátit.

Set<String> getFlavors(){
  return Collections.unmodifiableSet(flavors)
}

Takže pokud set unikne do kterékoli jiné části vloženého jinou ClassLoader a odkaz je tam stále, celý strom tříd + ClassLoader budou unikly. Aby se zabránilo, že kopie se HashMap je nezbytné new LinkedHashSet(new ArrayList(){{add("xxx);add("yyy");}}). Není to tak roztomilý nic víc. I nepoužívají idiom, já, místo toho to je jako new LinkedHashSet(Arrays.asList("xxx","YYY"));

Odpovězeno 25/01/2011 v 11:12
zdroj uživatelem

hlasů
18

Načítá mnoho tříd mohou přidat nějaké milisekund na začátek. V případě, že při spuštění není tak kritická a jste pohled na efektivitu tříd po uvedení do provozu není žádný rozdíl.

package vanilla.java.perfeg.doublebracket;

import java.util.*;

/**
 * @author plawrey
 */
public class DoubleBracketMain {
    public static void main(String... args) {
        final List<String> list1 = new ArrayList<String>() {
            {
                add("Hello");
                add("World");
                add("!!!");
            }
        };
        List<String> list2 = new ArrayList<String>(list1);
        Set<String> set1 = new LinkedHashSet<String>() {
            {
                addAll(list1);
            }
        };
        Set<String> set2 = new LinkedHashSet<String>();
        set2.addAll(list1);
        Map<Integer, String> map1 = new LinkedHashMap<Integer, String>() {
            {
                put(1, "one");
                put(2, "two");
                put(3, "three");
            }
        };
        Map<Integer, String> map2 = new LinkedHashMap<Integer, String>();
        map2.putAll(map1);

        for (int i = 0; i < 10; i++) {
            long dbTimes = timeComparison(list1, list1)
                    + timeComparison(set1, set1)
                    + timeComparison(map1.keySet(), map1.keySet())
                    + timeComparison(map1.values(), map1.values());
            long times = timeComparison(list2, list2)
                    + timeComparison(set2, set2)
                    + timeComparison(map2.keySet(), map2.keySet())
                    + timeComparison(map2.values(), map2.values());
            if (i > 0)
                System.out.printf("double braced collections took %,d ns and plain collections took %,d ns%n", dbTimes, times);
        }
    }

    public static long timeComparison(Collection a, Collection b) {
        long start = System.nanoTime();
        int runs = 10000000;
        for (int i = 0; i < runs; i++)
            compareCollections(a, b);
        long rate = (System.nanoTime() - start) / runs;
        return rate;
    }

    public static void compareCollections(Collection a, Collection b) {
        if (!a.equals(b) && a.hashCode() != b.hashCode() && !a.toString().equals(b.toString()))
            throw new AssertionError();
    }
}

tisky

double braced collections took 36 ns and plain collections took 36 ns
double braced collections took 34 ns and plain collections took 36 ns
double braced collections took 36 ns and plain collections took 36 ns
double braced collections took 36 ns and plain collections took 36 ns
double braced collections took 36 ns and plain collections took 36 ns
double braced collections took 36 ns and plain collections took 36 ns
double braced collections took 36 ns and plain collections took 36 ns
double braced collections took 36 ns and plain collections took 36 ns
double braced collections took 36 ns and plain collections took 36 ns
Odpovězeno 31/01/2013 v 14:46
zdroj uživatelem

hlasů
16

K vytvoření sady můžete použít metodu varargs tovární namísto dvojité vzpěry inicializace:

public static Set<T> setOf(T ... elements) {
    return new HashSet<T>(Arrays.asList(elements));
}

Knihovna Sbírky Google má spoustu výhodných metod, jako je tato, stejně jako spoustu dalších užitečných funkcí.

Co se týče neznáma idiom je, já to setkávají a používat jej v kódu výroby po celou dobu. Byl bych spíše o programátory, kteří se zmást idiom bylo dovoleno psát výrobní kód.

Odpovězeno 29/05/2009 v 05:20
zdroj uživatelem

hlasů
9

Účinnost stranou, málokdy jsem našel sám sebe, kteří chtějí pro tvorbu deklarativní sběru mimo unit testů. Věřím, že syntaxe dvojitá vzpěra je velmi čitelný.

Dalším způsobem, jak dosáhnout deklarativní výstavbu seznamů specificky je použít Arrays.asList(T ...)jako tak:

List<String> aList = Arrays.asList("vanilla", "strawberry", "chocolate");

Omezení tohoto přístupu je, samozřejmě, že nemůžete ovládat specifický typ seznamu, který bude vygenerován.

Odpovězeno 29/05/2009 v 04:59
zdroj uživatelem

hlasů
7

Tam je obecně nic obzvlášť neefektivní o tom. To není obecně nezáleží na JVM, že jste udělal podtřídy a přidal konstruktor to--, že je to normální, každodenní, co dělat v objektově orientovaném jazyce. Neumím si představit docela nepřirozený případech, kdy by mohly způsobit neefektivnost tím, že dělá to (například máte opakovaně zvanou metodu, která končí přijetím směs různých tříd, protože této podtřídy, zatímco obyčejná třída předaný bude zcela predictable- - v druhém případě se JIT překladač mohl dělat optimalizací, které nejsou proveditelné v první). Ale opravdu si myslím, že případy, kdy to bude záleží jsou velmi nepřirozený.

Já bych vidět problém spíše z hlediska, zda chcete „nepořádek věci do pořádku“ se spoustou anonymních tříd. Jako hrubé vodítko, zvažte použití idiom nic víc, než byste použít, řekněme, anonymní třídy pro zpracování událostí.

In (2), že jste uvnitř konstruktoru objektu, tak „to“ se vztahuje k objektu máte budovat. To nijak neliší od jakéhokoli jiného konstruktoru.

Pokud jde o (3), které opravdu záleží na tom, kdo se udržuje svůj kód, myslím. Pokud si nevíte to v předstihu, pak měřítkem, že bych navrhnout pomocí je „vidíte to ve zdrojovém kódu na JDK?“ (v tomto případě, nevzpomínám si, že viděl mnoho anonymních initialisers, a už vůbec ne v případě, že je to jediný obsah anonymní třídy). Ve většině středně velkých projektů, bych tvrdit, jste opravdu bude muset své programátory k pochopení zdroje v určitém místě nebo jiný JDK, takže jakákoliv syntaxe nebo idiom používá není „lovnou zvěří“. Kromě toho, řekl bych, školit lidi na této syntaxi, pokud máte kontrolu nad kdo udržuje kód, jiný komentář nebo se jim vyhnout.

Odpovězeno 29/05/2009 v 06:26
zdroj uživatelem

hlasů
4

Byl jsem to výzkum a rozhodl se udělat víc do hloubky testu, než je stanovené platnou odpověď.

Zde je kód: https://gist.github.com/4368924

a toto je můj závěr

Byl jsem překvapen, když zjistil, že ve většině běhu testuje vnitřní zahájení byl vlastně rychlejší (téměř dvojnásobek v některých případech). Při práci s velkými čísly se zdá, že přínos pro slábnout.

Zajímavé je, že v případě, že tvoří 3 objekty na smyčce ztrácí Je RANS dávek dříve než v ostatních případech. Nejsem si jist, proč se to děje a další testování by mělo být provedeno pro dosažení nějaké závěry. Vytvoření konkrétní implementace může pomoci, aby se zabránilo definici třídy být přeložen (je-li to, co se děje)

Nicméně je jasné, že není moc nad hlavou je pozorována ve většině případů k jedné budově položky, a to i při velkém počtu.

Jedna sada zpět by byla skutečnost, že každý z dvojitých výztužnými iniciací vytvoří nový soubor třídy, který přidá celý disk blok k velikosti naší aplikace (nebo o 1k při stlačení). Díky malým rozměrům, ale pokud je použit na mnoha místech, že by mohly mít vliv. Pomocí těchto 1000krát a ty jsou potenciálně přidání celý MiB vám applicaiton, které mohou být o na embedded prostředí.

Můj závěr? Může to být v pořádku používat tak dlouho, dokud nebylo zneužito.

Dej mi vědět, co si myslíš :)

Odpovězeno 24/12/2012 v 13:17
zdroj uživatelem

hlasů
3

I když tato syntaxe může být výhodné, ale také přidává spoustu tomuto 0 $ odkazy, protože tyto stanou vnořené, a to může být obtížné krok ladění do Inicializátory pokud zarážky jsou nastaveny na každé z nich. Z tohoto důvodu, jen doporučuji používat to pro banální tvůrci, zejména nastavenými na konstant a místech, kde anonymní podtřídy nezáleží (jako žádný serializaci zapojen).

Odpovězeno 18/06/2014 v 21:46
zdroj uživatelem

hlasů
3

Mario Gleichman popisuje, jak používat Java 1.5 generické funkce pro simulaci Scala List literály, ale bohužel budete vítr s neměnnými seznamů.

Ten definuje tuto třídu:

package literal;

public class collection {
    public static <T> List<T> List(T...elems){
        return Arrays.asList( elems );
    }
}

a používá ho z ní vyplývající:

import static literal.collection.List;
import static system.io.*;

public class CollectionDemo {
    public void demoList(){
        List<String> slist = List( "a", "b", "c" );
        List<Integer> iList = List( 1, 2, 3 );
        for( String elem : List( "a", "java", "list" ) )
            System.out.println( elem );
    }
}

Google sbírky, nyní součástí Guava podporuje podobný nápad na seznam staveb. V tomto rozhovoru , Jared Levy říká:

[...] jsou nejvíce používané znaky, které se objevují v téměř každé třídy Java píšu, jsou statické metody, které snižují počet opakovaných úhozů v kódu Java. Je to tak pohodlné, budou moci zadávat příkazy jako následující:

Map<OneClassWithALongName, AnotherClassWithALongName> = Maps.newHashMap();

List<String> animals = Lists.immutableList("cat", "dog", "horse");

07.10.2014: Kéž by to mohlo být tak jednoduché, jak Python:

animals = ['cat', 'dog', 'horse']

Odpovězeno 22/10/2009 v 07:06
zdroj uživatelem

hlasů
3

Druhá I Nat odpověď, s výjimkou bych použil smyčku namísto vytváření a okamžitě hodil implicitní seznam z asList (prvky):

static public Set<T> setOf(T ... elements) {
    Set set=new HashSet<T>(elements.size());
    for(T elm: elements) { set.add(elm); }
    return set;
    }
Odpovězeno 29/05/2009 v 05:50
zdroj uživatelem

hlasů
2

inicializace Double-ortéza je zbytečné hack, který může představit úniky paměti a další problémy

Neexistuje žádný legitimní důvod, proč používat tento „trik“. Guava poskytuje pěkné neměnné kolekce , které obsahují statické továren a stavitelů, což vám umožní naplnit svou sbírku, kde je deklarována v čistém, čitelné a bezpečné syntaxe.

Příklad v otázce se stane:

Set<String> flavors = ImmutableSet.of(
    "vanilla", "strawberry", "chocolate", "butter pecan");

Nejen že je to kratší a čitelnější, ale vyhýbá se četné problémy s dvojitě vyztuženy vzoru popsaného v další odpovědi . Jistě, to hraje podobně jako přímo postavený HashMap, ale je to nebezpečné a náchylné k chybám, a existují lepší možnosti.

Kdykoli se ocitnete s ohledem na dvojitou připravila inicializaci byste měli znovu přezkoumat své API nebo zavést nové , aby tento problém řádně vyřešit, spíše než využít syntaktických triků.

Náchylné k chybám se příznaky to anti-vzor .

Odpovězeno 12/04/2017 v 20:24
zdroj uživatelem

hlasů
2

1) To bude vyžadovat přidat () pro každého člena. Pokud můžete najít efektivnější způsob, jak zařazovat body do hash set, pak ji využít. Všimněte si, že vnitřní třída bude pravděpodobně vytvářet nesmyslné, pokud jste citlivý na to.

2) Zdá se mi, jako by kontext je objekt vrácen „nové“, což je HashSet.

3) Pokud je třeba se ptát ... Spíš: budou lidé, kteří přijdou po vás to vědí, nebo ne? Je snadné pochopit a vysvětlit? Pokud můžete odpovědět „ano“ na obě, bez obav používat.

Odpovězeno 29/05/2009 v 04:56
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more