JavaRush /Java 博客 /Random-ZH /双大括号初始化
Joysi
第 41 级

双大括号初始化

已在 Random-ZH 群组中发布

1.双括号初始化

使用双大括号初始化(以下简称双大括号初始化)是一种 Java 工具,用于在声明列表、集合和映射等集合的同时创建它们。
双大括号初始化 - 1
当您需要具有固定元素的列表(例如支持的产品或货币的列表)时,在初始化列表的同时声明该列表可以提高代码的可读性。这就是双括号初始化越来越受欢迎的原因,因为没有其他标准方法可以在代码中同时初始化来创建集合。不幸的是,与其他编程语言不同,Java 不支持文字集合。由于这个限制,即使创建一个包含少量元素的不可修改列表,也会迫使我们以重复调用的形式编写许多行代码,add()以添加所需的元素并进行最终包装:
List<Integer> list = new ArrayList<>();
list.add(2);
list.add(3);
list.add(5);
list.add(7);
List<Integer> unmodifiableList = Collections.unmodifiableList(list);
这是不必要的冗余描述,可以简化。让我们以一种方便的方式填充静态列表,即在初始化期间直接在静态块中填充,这就是Double brace初始化将帮助我们的,允许我们将所有内容写在一行中:
List<Integer> list = Collections.unmodifiableList(new ArrayList<Integer>() {{
        add(2);
        add(3);
        add(5);
}});
同样,Double brace初始化会帮助我们填写值 和HashMap
Map<Integer, String> intToString = new HashMap<Integer, String>(){{
         put(1, "one");
         put(2, "two");
         put(3, "three");
 }};
这一切看起来都很优雅,但它有其缺点,这使得双括号初始化成为一种反模式。我们将在下一章进一步讨论它们。

双括号初始化的优点和缺点。

Double大括号初始化使用匿名内部类的创建。然而,最初隐藏在表面上的东西,Double brace初始化会创建一个类,并在每次使用它时进一步初始化其实例。此外,使用了对此私有类的隐藏引用,这可能会导致内存泄漏。您也不能对泛型使用幽灵运算符(菱形运算符 < >),因为我们无法访问匿名类的内部。
(译者:再次更详细地说:
在第一个之后{,创建了一个内部匿名类,在第二个之后,{在创建该类的实例时进行初始化,在此期间我们可以访问外部(相对于匿名)类。)
优点:
  1. 减少代码行数
  2. 在一个表达式中创建和初始化。
缺点:
  1. 创建一个对您隐藏的匿名类。
  2. 每次我们使用它的实例时,这都会给我们带来额外的费用。
  3. 每次创建对其的隐藏引用时,都可能导致内存泄漏。
结论:由于上述缺点以及双大括号替代方案的存在,初始化在 Java 世界中被视为反模式。 拯救小猫

Java 中双大括号初始化的替代方案

好消息是,在 Java 中还有其他方法可以实现相同的目标。我们可以使用 Collection 类中的 Copy 构造函数在一行代码中实现 ArrayList 的创建和初始化,如下所示:
List<Integer> list = Collections.unmodifiableList(new ArrayList<>(Arrays.asList(2, 3, 5)));
Arrays.asList()将返回一个传递给ArrayList复制构造函数的固定长度列表。请记住从Arrays.asList()和返回的固定长度列表之间的区别Collections.unmodifiableList():您不能添加或删除ArrayList- 的元素,但您可以使用 来通过索引更改元素set(),而对于 所返回的列表则无法执行此操作Collections.unmodifiableList()。如果你想获得一个小列表,这是最好的方法,尽管它对于其他集合来说不太透明Set,所以你必须List在创建Set-a 之前创建它。但这仍然比双括号初始化更好,因为在这种情况下,每次使用时都不会创建额外的内部匿名类。如果您运行的是 Java 8,您还有另一种替代方法。JDK 8 Stream API 将通过将输出Stream Factory方法组合到集合中来帮助您创建小型集合List
List<String> list = Collections.unmodifiableList(Stream.of("abc", "bcd", "cde").collect(toList()));
Set您可以使用以下Collectors.toSet()方法 代替Collectors.toList()
Set<String> set = Collections.unmodifiableSet(Stream.of("abc", "bcd", "cde").collect(toSet()));
顺便说一句,Stream collect方法并不能保证它们生成的集合不会被更改。在 Java 8 中,它们返回的集合(例如 - ArrayListHashSetHashMap)非常常见(我们可以更改它们),但这一事实可能会在未来的 JDK 版本中得到纠正。Double brace这就是关于Java 初始化的全部内容。该模板对于测试和演示来说是可以接受的,但对于生产使用来说还不够好。由于其固有的缺点,双括号初始化如今已成为一种反模式,特别是考虑到可用的替代方案。我自己仍然使用这个构造来初始化静态地图,仅此而已。因为我更喜欢通过与构造函数中的创建相结合来List创建。如果我使用 Java 8 - 使用 Stream API 和. 相关文章:如果您喜欢本教程并且想要了解有关 Java 编程模式、原理和最佳实践的更多信息,您可能还想查看我们网站上的其他文章。 推荐阅读:如果您想了解更多有关模式和最佳实践的信息,您应该阅读Joshua Bloch 的《有效编程》,没有一本书可以取代它。而如果你已经精通Java,并且正在寻找一本关于设计模式的书,其幽默的讲授风格有趣且易于阅读,请关注《Head First》。设计模式”CollectionsArray.asListcollect()
译者:我特意提供了布洛赫原著的链接,因为它翻译成俄语并不成功(例如,Builder = 构造函数)。
文章翻译什么是 Java 中的双括号初始化?反模式示例(2015 年 10 月发布)。
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION