Java9中集合的重载便利工厂方法有什么意义

Java9中集合的重载便利工厂方法有什么意义,java,collections,variadic-functions,java-9,Java,Collections,Variadic Functions,Java 9,Java9提供了创建不可变列表的功能。最后,创建列表非常简单,如下所示: List<String> list = List.of("foo", "bar"); List List=List.of(“foo”、“bar”); 但是这个方法有12个重载版本,11个有0到10个元素,还有一个有var args static <E> List<E> of(E... elements) 静态列表(E…元素) Set和Map的情况也是如此 既然有一个var-ar

Java9提供了创建不可变列表的功能。最后,创建列表非常简单,如下所示:

List<String> list = List.of("foo", "bar");
List List=List.of(“foo”、“bar”);
但是这个方法有12个重载版本,11个有0到10个元素,还有一个有var args

static <E> List<E>  of(E... elements)
静态列表(E…元素)
Set
Map
的情况也是如此

既然有一个var-args方法,那么有额外的11个方法有什么意义呢


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

正如您所怀疑的,这是一种性能提升。Vararg方法“在引擎盖下”创建一个数组,使用直接接受1-10个参数的方法可以避免这种冗余数组的创建。

从它本身-

说明-

这些将包括varargs重载,因此没有固定的限制 关于集合大小。但是,这样创建的集合实例 可以调整为更小的尺寸。特殊情况API(固定参数 将为最多十个元件提供过载保护当这个 在API中引入了一些混乱,避免了数组分配, 初始化,以及 varargs调用。重要的是,无论调用的是固定arg还是varargs重载,调用站点的源代码都是相同的


编辑-要添加动机,正如@CKing在评论中已经提到的:

非目标-

它的目标不是支持高性能、可扩展的集合 具有任意数量的元素重点是小型收藏

动机-

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

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

你也可以反过来看。由于varargs方法可以接受数组,因此这种方法可以作为将数组转换为
列表的替代方法

String []strArr = new String[]{"1","2"};
List<String> list = List.of(strArr);
String[]strArr=新字符串[]{“1”,“2”};
List List=List.of(strArr);
这种方法的替代方法是使用
数组.asList
,但在这种情况下对
列表
所做的任何更改都会反映在数组中,而
列表.of
的情况则不同。因此,当您不希望
列表
与数组同步时,可以使用
List.of


注意规范中给出的理由对我来说似乎是一种微观优化。(这一点现在已由API的所有者在回答意见中确认)

您可能会发现Josh Bloch的《有效Java》(第二版)第42项中的以下段落很有启发性:

每次调用varargs方法都会导致数组分配和初始化。如果你根据经验确定你负担不起这笔费用,但你需要varargs的灵活性,那么有一种模式可以让你既吃蛋糕,又吃蛋糕。假设您已经确定95%的方法调用具有三个或更少的参数。然后声明该方法的五个重载,其中一个重载通过三个普通参数分别为零,另一个重载是一个varargs方法,当参数数量超过三个[…]时使用

根据:便利工厂方法返回的集合比其可变等价物更节省空间

在Java 9之前:

Set<String> set = new HashSet<>(3);   // 3 buckets

set.add("Hello");
set.add("World");
set = Collections.unmodifiableSet(set);
Set<String> set = Set.of("Hello", "World");

在上面的
Set
实现中,只创建一个对象,由于开销最小,因此保存数据所需的空间将非常小。

此模式用于优化接受varargs参数的方法

如果您能发现,在大多数情况下,您只使用了其中的两个参数,那么您可能希望使用最常用的参数量定义一个方法重载:

public void foo(int num1);
public void foo(int num1, int num2);
public void foo(int num1, int num2, int num3);
public void foo(int... nums);
这将帮助您避免在调用varargs方法时创建数组。用于性能优化的模式:

List<String> list = List.of("foo", "bar");
// Delegates call here
static <E> List<E> of(E e1, E e2) { 
    return new ImmutableCollections.List2<>(e1, e2); // Constructor with 2 parameters, varargs avoided!
}
List List=List.of(“foo”、“bar”);
//代表们在这里发言
(e1,e2){
返回新的ImmutableCollections.List2(e1,e2);//使用2个参数的构造函数,避免使用varargs!
}
更有趣的是,从3个参数开始,我们再次将其委托给varargs构造函数:

static <E> List<E> of(E e1, E e2, E e3) { 
    return new ImmutableCollections.ListN<>(e1, e2, e3); // varargs constructor
}
静态列表(e1,e2,e3){
返回新的ImmutableCollections.ListN(e1,e2,e3);//varargs构造函数
}

现在看来这似乎很奇怪,但正如我所猜测的,这是为将来的改进保留的,并且作为一个选项,所有构造函数
List3(3个参数)、List7(7个参数)都可能过载…
等等。

您已经回答了自己的问题-使用0-10个参数重载它会跳过不必要的数组创建。@Marco13我投票重新打开,因为有很多问题都超越了技术。同样投票重新开放,因为考虑到这些功能现在在
java
中可用,人们会搜索“java 9 collection.of”而不是“Guava colleciton.of”。@Marco13我相信创建一个规范问题并将这两个问题作为重复问题指向它是有意义的。在我们这样做之前,我认为这个问题应该继续存在。我不想占用这个问题的评论空间来讨论这个问题,所以让我们看看其他人怎么说。我投票重新开始。其他API(Guava、EnumSet)中类似重载的驱动程序不同-它们提供重载是因为当时不存在
@SafeVarargs
,而JEP 269中重载的驱动程序则不存在。@StefanZobel同意;特别是因为一般的讨论点是,这是一个要排除的微观优化
List<String> list = List.of("foo", "bar");
// Delegates call here
static <E> List<E> of(E e1, E e2) { 
    return new ImmutableCollections.List2<>(e1, e2); // Constructor with 2 parameters, varargs avoided!
}
static <E> List<E> of(E e1, E e2, E e3) { 
    return new ImmutableCollections.ListN<>(e1, e2, e3); // varargs constructor
}