“Java的效率”;双大括号初始化“;?

“Java的效率”;双大括号初始化“;?,java,performance,collections,initialization,Java,Performance,Collections,Initialization,在最上面的答案中提到了一个非常诱人的语法: Set<String> flavors = new HashSet<String>() {{ add("vanilla"); add("strawberry"); add("chocolate"); add("butter pecan"); }}; Set-flavors=new-HashSet(){{ 添加(“香草”); 添加(“草莓”); 添加(“巧克力”); 添加(“黄油山核桃”); }}

在最上面的答案中提到了一个非常诱人的语法:

Set<String> flavors = new HashSet<String>() {{
    add("vanilla");
    add("strawberry");
    add("chocolate");
    add("butter pecan");
}};
Set-flavors=new-HashSet(){{
添加(“香草”);
添加(“草莓”);
添加(“巧克力”);
添加(“黄油山核桃”);
}};
这个习惯用法创建了一个匿名内部类,其中只有一个实例初始值设定项,它“可以使用包含范围内的任何[…]方法”

主要问题:这是不是听起来低效?是否应将其使用限制为一次性初始化?(当然还有炫耀!)

第二个问题:新哈希集必须是实例初始值设定项中使用的“this”。。。有人能解释一下这个机制吗

第三个问题:这个习惯用法是否太晦涩,无法在生产代码中使用

总结:非常非常好的答案,谢谢大家。关于问题(3),人们认为语法应该清晰(尽管我建议偶尔发表评论,特别是如果您的代码将传递给可能不熟悉它的开发人员)

关于问题(1),生成的代码应该快速运行。额外的.class文件确实会导致jar文件混乱,程序启动稍微缓慢(感谢@coobird的测量)@Thilo指出,垃圾收集可能会受到影响,在某些情况下,额外加载的类的内存成本可能是一个因素

问题(2)对我来说是最有趣的。如果我理解了答案,那么DBI中发生的事情就是匿名内部类扩展了由新操作符构造的对象的类,因此有一个引用正在构造的实例的“this”值。非常整洁

总的来说,DBI给我的印象是一种智力上的好奇心。Coobird和其他人指出,使用Arrays.asList、varargs方法、Google集合和建议的Java7集合文本可以实现相同的效果。较新的JVM语言,如Scala、JRuby和Groovy,也为列表构造提供了简洁的符号,并且与Java具有良好的互操作性。考虑到DBI会使类路径变得杂乱无章,使类加载速度慢了一点,并使代码更加晦涩,我可能会回避它。然而,我打算把这一点告诉一位朋友,他刚刚拿到了他的SCJP,并且喜欢关于Java语义的善意辩论!;-)谢谢大家

2017年7月:Baeldung的双支架初始化,并认为它是一个反模式

2017年12月:@Basil Bourque指出,在新的Java 9中,您可以说:

Set<String> flavors = Set.of("vanilla", "strawberry", "chocolate", "butter pecan");
Set香料=一套(“香草”、“草莓”、“巧克力”、“奶油山核桃”);

这肯定是一条路要走。如果您仍坚持使用早期版本,请查看。

参加以下测试课程:

public class Test {
  public void test() {
    Set<String> flavors = new HashSet<String>() {{
        add("vanilla");
        add("strawberry");
        add("chocolate");
        add("butter pecan");
    }};
  }
}
在我看来,这并不是非常低效。如果我担心像这样的东西的性能,我会分析它。上面的代码回答了您的问题#2:您位于内部类的隐式构造函数(和实例初始值设定项)中,因此“
this
”指的是这个内部类

是的,这种语法是晦涩难懂的,但是注释可以澄清晦涩难懂的语法用法。为了澄清语法,大多数人都熟悉静态初始值设定项块(JLS 8.7静态初始值设定项):

您也可以使用类似的语法(不使用单词“
static
”)来使用构造函数(JLS 8.6实例初始值设定项),尽管我从未在生产代码中使用过这种语法。这是不太为人所知的

public class Sample2 {
    private final String someVar;

    // This is an instance initializer
    {
        String temp = null;
        ..... // block of code setting temp
        someVar = temp;
    }
}
如果没有默认构造函数,则编译器会将
{
}
之间的代码块转换为构造函数。记住这一点,解开双大括号代码:

public void test() {
  Set<String> flavors = new HashSet<String>() {
      {
        add("vanilla");
        add("strawberry");
        add("chocolate");
        add("butter pecan");
      }
  };
}
公共无效测试(){
Set-flavors=new-HashSet(){
{
添加(“香草”);
添加(“草莓”);
添加(“巧克力”);
添加(“黄油山核桃”);
}
};
}
编译器将最内部大括号之间的代码块转换为构造函数。最外层的大括号分隔匿名内部类。这是使所有内容都非匿名的最后一步:

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

class MyHashSet extends HashSet<String>() {
    public MyHashSet() {
        add("vanilla");
        add("strawberry");
        add("chocolate");
        add("butter pecan");
    }
}
公共无效测试(){
Set flavors=new MyHashSet();
}
类MyHashSet扩展了HashSet(){
公共MyHashSet(){
添加(“香草”);
添加(“草莓”);
添加(“巧克力”);
添加(“黄油山核桃”);
}
}
出于初始化的目的,我想说没有任何开销(或者说开销很小,可以忽略不计)。但是,每次使用
flavors
都不会违背
HashSet
,而是违背
MyHashSet
。这可能会有一小部分(而且可能可以忽略不计)开销。但再一次,在我担心它之前,我会分析它

同样,对于您的问题#2,上面的代码是双大括号初始化的逻辑和显式等价物,它使“
this
”所指的地方变得明显:扩展
HashSet
的内部类

如果您对实例初始值设定项的详细信息有疑问,请查看文档中的详细信息

  • 这将为每个成员调用
    add()
    。如果您能找到一种更有效的方法将项目放入哈希集中,那么就使用它。请注意,如果您对此很敏感,那么内部类可能会生成垃圾

  • 在我看来,上下文似乎是
    new
    返回的对象,即
    哈希集

  • 如果你需要问。。。更有可能的是:在你之后来的人是否知道这一点?它容易理解和解释吗?如果你能对两者都回答“是”,请随意使用它


  • 撇开效率不谈,我很少希望在单元测试之外创建声明性集合。我相信双括号语法是非常可读的

    实现列表声明性构造的另一种方法是使用
    数组。asList(T…
    如下所示:

    List<String> aList = Arrays.asList("vanilla", "strawberry", "chocolate");
    
    List aLi
    
    public void test() {
      Set<String> flavors = new MyHashSet();
    }
    
    class MyHashSet extends HashSet<String>() {
        public MyHashSet() {
            add("vanilla");
            add("strawberry");
            add("chocolate");
            add("butter pecan");
        }
    }
    
    List<String> aList = Arrays.asList("vanilla", "strawberry", "chocolate");
    
    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
    
    List<String> list = new ArrayList<String>() {{
        add("Hello");
        add("World!");
    }};
    
    List<String> list = new ArrayList<String>() {
    
        // Instance initialization block
        {
            add("Hello");
            add("World!");
        }
    };
    
    List<Integer> intList = [1, 2, 3, 4];
    
    Set<String> strSet = {"Apple", "Banana", "Cactus"};
    
    Map<String, Integer> truthMap = { "answer" : 42 };
    
    List<String> l = new ArrayList<String>() {{
      add("Hello");
      add("World!");
    }};
    
    List<String> l = new ArrayList<String>();
    l.add("Hello");
    l.add("World!");
    
    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);
      }
    }
    
    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);
      }
    }
    
    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
    
    public static Set<T> setOf(T ... elements) {
        return new HashSet<T>(Arrays.asList(elements));
    }
    
    static public Set<T> setOf(T ... elements) {
        Set set=new HashSet<T>(elements.size());
        for(T elm: elements) { set.add(elm); }
        return set;
        }
    
    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 
                }
            };
        }
    }
    
        public Set<String> makeSet() {
            return new HashSet<String>() {
                {
                  add("hello"); // not HashSet anymore ...
                }
    
                @Override
                boolean add(String s){
    
                }
    
            };
        }
    
    package literal;
    
    public class collection {
        public static <T> List<T> List(T...elems){
            return Arrays.asList( elems );
        }
    }
    
    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 );
        }
    }
    
    Set<String> getFlavors(){
      return Collections.unmodifiableSet(flavors)
    }
    
    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();
        }
    }
    
    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
    
    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");
            }});
        }});
    }};
    
    Test$1$1$1.class
    Test$1$1$2.class
    Test$1$1.class
    Test$1.class
    Test.class
    
    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;
        }
    }
    
    String[] array = { "John", "Doe" };
    Map map = new HashMap() {{ put("John", "Doe"); }};
    
    Set<String> flavors = ImmutableSet.of(
        "vanilla", "strawberry", "chocolate", "butter pecan");