Java9:什么是集合工厂方法?

Java 9: What are collection factory methods?

Java 9 的到来为 Java 的集合 API 带来了许多新特性,其中之一就是集合工厂方法。

它们是什么以及如何正确实施它们?

注 1:为了防止使用原始类型,我选择为下面提到的每个 class 提供通用类型,方法是使用 E,代表一个Collection<E>.

的一个元素

注2:此答案可能会发生变化;如果出现拼写错误,请编辑此 post。

什么是集合工厂方法?

Java 中的集合工厂方法是一种静态方法,它提供了一种初始化 不可变 Collection<E>.

的简单方法

是不可变的,Collection<E>初始化后不能添加、删除或修改任何元素。

使用Java9,为以下接口提供集合工厂方法:List<E>Set<E>Map<K, V>

他们改进了什么?

直到 Java 9,还没有简单、通用的方法来初始化带有初始 elements/key-value 条目的 Collection<E>。以前,开发人员需要按如下方式初始化它们(假设泛型类型 EKV 已替换为 Integer):

  • List<Integer>
    • 下面的方法可以说是最简单的用初始元素初始化 List<Integer> 的方法,但是结果只是 List<Integer> 的一个视图;我们无法向 List<Integer> 添加或从中删除,但我们仍然可以使用 List#set 修改现有元素。
      • List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
    • 如果我们希望我们的 List<Integer> 完全可变,那么我们必须将它传递给 ArrayList<Integer> 的构造函数,例如:
      • List<Integer> mutableList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
  • Set<Integer>
    • A Set<Integer>List<Integer> 需要更多的代码来初始化初始元素(因为 List<Integer> 需要用初始元素初始化 Set<Integer>) ,可以在下面看到。
      • Set<Integer> mutableSet = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
  • Map<Integer, Integer>
    • A Map<Integer, Integer> 可以说是使用初始键值条目初始化最复杂的;但是,有多种方法可以解决这个问题。
      • 一种方法是先初始化一个空的 Map<Integer, Integer>,然后简单地调用 Map#put 来添加键值条目。
      • 另一种方法是使用带有两个大括号的匿名 class,这仍然需要调用 Map#put

我为什么要使用它们?

我认为集合工厂方法为开发人员提供了一种使用初始 elements/key-value 条目初始化 List<E>Set<E>Map<K, V> 的简洁方法,这可以通过下面的示例可以看出。

正确的语法是什么?

为简单起见,这些示例将用 Integer.

替换泛型类型 EKV
  • List<Integer>
    • List<Integer> list = List.of();
      • 初始化一个空的、不可变的List<Integer>
    • List<Integer> list = List.of(1);
      • 用一个元素初始化一个不可变 List<Integer>
    • List<Integer> list = List.of(1, 2);
      • 用两个元素初始化不可变 List<Integer>
    • List<Integer> list = List.of(1, 2, 3, 4, 5, ...);
      • 用可变数量的元素初始化不可变 List<Integer>
  • Set<Integer>
    • Set<Integer> set = Set.of();
      • 初始化一个空的、不可变的 Set<Integer>
    • Set<Integer> set = Set.of(1);
      • 用一个元素初始化一个不可变 Set<Integer>
    • Set<Integer> set = Set.of(1, 2);
      • 用两个元素初始化不可变 Set<Integer>
    • Set<Integer> set = Set.of(1, 2, 3, 4, 5, ...);
      • 用可变数量的元素初始化不可变 Set<Integer>
  • Map<Integer, Integer>
    • Map<Integer, Integer> map = Map.of();
      • 初始化一个空的、不可变的 Map<Integer, Integer>
    • Map<Integer, Integer> map = Map.of(1, 2);
      • 用一个键值对初始化一个不可变的Map<Integer, Integer>
      • 注意key是1,value是2.
    • Map<Integer, Integer> map = Map.of(1, 2, 3, 4);
      • 用两个键值条目初始化不可变 Map<Integer, Integer>
      • 请注意,键是 13,值是 24
    • Map<Integer, Integer> map = Map.ofEntries(Map.entry(1, 2), Map.entry(3, 4), ...);
      • 使用可变数量的键值条目初始化不可变 Map<Integer, Integer>

如您所见,这种新的初始化方法比它的前辈需要更少的代码。

我可以使用集合工厂方法来创建可变对象吗?

集合工厂方法创建的 Collection<E> 本质上是不可变的,但是我们可以将它们传递给 Collection<E> 实现的构造函数以生成可变版本:

  • List<Integer>
    • List<Integer> mutableList = new ArrayList<>(List.of(1, 2, 3, 4, 5));
  • Set<Integer>
    • Set<Integer> mutableSet = new HashSet<>(Set.of(1, 2, 3, 4, 5));
  • Map<Integer, Integer>
    • Map<Integer, Integer> mutableMap = new HashMap<>(Map.of(1, 2, 3, 4));