Java 9 中重载的便利工厂集合方法的意义何在

Java 9 附带了用于创建不可变列表的便捷工厂方法。最后,列表创建就像:

List<String> list = List.of("foo", "bar");

但是这种方法有12个重载版本,11个具有0到10个元素,一个具有var args。

static <E> List<E>  of(E... elements)

和 的情况也是如此。SetMap

既然有一个var args方法,那么多11个方法有什么意义呢?

我认为var-args创建了一个数组,因此其他11种方法可以跳过创建额外的对象,并且在大多数情况下,0-10个元素就可以了。这还有其他原因吗?


答案 1

JEP 文档本身 -

描述 -

这些将包括 varargs 重载,因此对集合大小没有固定限制。但是,可以针对较小的大小调整如此创建的集合实例。将为最多十个元素提供特殊情况的API(固定参数重载)。虽然这会在 API 中引入一些混乱,但它避免了 varargs 调用产生的数组分配、初始化和垃圾回收开销。值得注意的是,无论调用的是 fixed-arg 还是 varargs 重载,调用站点的源代码都是相同的。


编辑 - 为了增加动机,正如@CKing的评论中已经提到的那样:

非目标 -

支持具有任意数量元素的高性能、可缩放集合不是目标。重点是小型集合

动机 -

创建一个小型的、不可修改的集合(比如说,一个集合)涉及构造它,将其存储在局部变量中,并在其上多次调用add(),然后包装它。

Set<String> set = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("a", "b", "c")));

Java 8 流 API 可以通过组合流工厂方法和收集器来构造小型集合。

// Java 8
Set<String> set1 = Collections.unmodifiableSet(Stream.of("a", "b", "c").collect(Collectors.toSet()));

通过提供用于创建小型集合实例的库 API,可以获得集合文本的大部分好处,与更改语言相比,成本和风险会大大降低。例如,用于创建小型 Set 实例的代码可能如下所示:

// Java 9 
Set set2 = Set.of("a", "b", "c");

答案 2

你可能会发现Josh Bloch的《Effective Java》(第2版)第42项的以下段落很有启发性:

varargs 方法的每次调用都会导致数组分配和初始化。如果你已经根据经验确定你负担不起这个成本,但你需要变色剂的灵活性,那么有一种模式可以让你拥有蛋糕并吃掉它。假设您已确定对某个方法的 95% 的调用具有三个或更少的参数。然后声明该方法的五个重载,每个重载一个,每个重载到三个普通参数,以及一个varargs方法,用于当参数数超过三个[...]