1. 概述

在本文中,我们将展示如何使用双花括号在单个Java表达式中创建和初始化对象

我们还将研究为什么这种技术被认为是一种反面模式

2.标准初始化方式

通常我们按如下方式初始化和填充Set:

    @Test
    public void test_InitializeSetWithoutDoubleBraces() {
        final Set<String> countries = new HashSet<>();
        countries.add("CHN");
        countries.add("JPN");
        countries.add("USA");
        assertTrue(countries.contains("CHN"));
    }

从上面的代码可以看出:

  1. 创建HashSet的实例。

  2. 将国家简写添加到HashSet

  3. 最后,我们断言国家简写是否存在于HashSet中

3. 双花括号初始化

实际上,在Java中我们可以在单个语句中完成创建和初始化。

    @Test
    public void test_InitializeSetWithDoubleBraces() {
        Set<String> countries = new HashSet<String>() {
            {
                add("CHN");
                add("JPN");
                add("USA");
            }
        };
        assertTrue(countries.contains("CHN"));
    }

从上面的代码可以看出:

  1. 创建一个扩展HashSet的匿名内部类
  2. 提供实例初始化块,该块调用add方法并将国家简写添加到HashSet
  3. 最后,我们可以断言该国家简写是否存在于HashSet中

4. 使用双花括号初始化的优点

使用双花括号有一些简单的优点:

  • 与本地创建和初始化方式相比,代码行更少
  • 代码更具可读性
  • 创建初始化在同一表达式中完成

5. 使用双花括号初始化的缺点

使用双花括号的缺点:

  • 模糊,不是广为人知的初始化方式
  • 每次我们使用它时都会创建一个额外的类
  • 不支持使用Java 7中引入的<>
  • 如果我们尝试扩展的类标记为*final,*则不起作用
  • 保存对封闭实例的隐藏引用,这可能导致内存泄漏

正是由于这些缺点,双花括号初始化被认为是反面模式

6.其他替代方案

那有哪些替代的方案呢?

6.1 流工厂方法

可以利用Java 8 Stream API来初始化我们的Set

    @Test
    public void test_InitializeWithStream() {
        Set<String> countries = Stream.of("CHN", "JPN", "USA")
                .collect(collectingAndThen(toSet(), Collections::unmodifiableSet));

        assertTrue(countries.contains("CHN"));
    }

6.2 Java 9集合工厂方法

当然,也可以使用Java 9中添加的工厂方法。

    @Test
    public void test_InitializeWithCollectionFactoryMethods() {
        Set<String> countries = Set.of("CHN", "JPN", "USA");

        assertTrue(countries.contains("CHN"));
    }

7.结论

在本文中中,我们讨论了双花括号的用法及其优缺点。

最后,往常一样,代码可以在Github上找到。