java 中的 String[]::new 和 new String[] 有区别吗?

Is there a difference between String[]::new and new String[] in java?

我正在使用

将 ArrayList 转换为数组
ArrayList<String> var1 = new ArrayList<>();
for(condition){
// Add items to var1
}

return var1.toArray(new String[]{})

我的 IDE 建议我将最后一行更改为

return var1.toArray(String[]::new)

这只是更好的约定,还是对编译时或内存使用也有一些好处。

"String[]::new" 是一个方法参考。它与“new String[]”基本相同。有关详细信息,请参阅 Method References

String[]::new 是一个函数。它不创建新的字符串数组,它定义了一个创建新字符串数组的函数。这就像蛋糕和制作蛋糕的食谱之间的区别。一种由面粉和糖衣等组成。另一个只是文字和纸张。完全不同但相关的东西,因为食谱可以让你做蛋糕(甚至可以做任何数量的蛋糕!)

String[]::new 是 shorthand* 对于:

public String[] makeNewStringArray(int size) {
    return new String[size];
}

仅仅编写根本不构成任何字符串数组; 调用该函数每次调用时都会生成一个字符串数组。

示例:

IntFunction<String[]> stringArrayMaker = String[]::new;
String[] size10 = stringArrayMaker.apply(10);

好的,那么推荐呢?

你写的有点不规范; new String[0] 更标准。那么让我们比较一下 new String[0]String[]::new.

这个参数唯一的意义就是让arraylist知道你想要什么类型。你会认为 arraylist 已经知道(毕竟它是一个 ArrayList<String>!)但是由于泛型擦除(一个相当复杂的主题),toArray 的代码无法知道你的内容想要,所以,你必须指定。

new String[0] 最终生成一个长度为 0 的字符串数组,然后立即将其丢弃。这感觉很浪费,但垃圾收集就是这样,'quick garbage'(对象创建和丢弃非常快并且从不与其他线程共享)几乎完全免费。此方法 (toArray(T[])) 的工作原理如下:如果传入数组与需要的一样大或大于需要的数组,则将其填充并返回。如果太小,则创建一个具有相同组件类型且大小合适的新数组,填充一个,然后返回一个。

因此,您会认为 var1.toArray(new String[var1.size()]) 是最有效的。但是 JMH 告诉我完全没有区别。这表明 java 在处理短暂垃圾方面是多么高效(当我说 'short lived garbage is free' 时,我是认真的。几乎不可能见证它的成本)。

函数式方法(您传递 String[]::new 的地方)意味着此函数将负责创建数组,而 toArray 本身仅依赖于它得到的内容。这..也可以正常工作。它最终在你的 class 文件中的某个地方创建了一个方法。

所以,真的没关系。我发现 IDE 在这里过于说教了。 String[]::new 提出了一种新方法,仅 class space 中的开销可能意味着它最终效率较低,即使垃圾的创建是更容易理解的低效率。

但是,我们真的很挑剔。字面意思是纳秒 - 你永远不会注意到。

做任何你认为最易读的事情(虽然我会避开 new String[]{} - 它本身没有错,但它不是很常见并且它没有 new String[0] 的好处 - 可能如果无关紧要,我们会做社区做的事。

*) 这有点过于简单了,但并没有太多。