从java8文档中我可以看到::new
用于引用构造函数方法。
但是当涉及到此声明时,
stream.toArray(String[]::new)
String[]::new
是什么意思?不应有一个名为String[]
的类,它非常la脚,我无法解释其实际含义。
答案 0 :(得分:4)
String[]::new
这是用于以下方法的lambda:
public String[] create(int size) {
return new String[size];
}
答案 1 :(得分:4)
我想说现有的答案可以提供一些见识,但是他们都还没有谈论IntFunction<R>
。
要补充说明的是,在Stream.toArray(String[]::new)
上下文中,它表示一个IntFunction
实现,例如:
new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
}
其中的代码创建了一个新分配的String[]
,其大小为value
,并产生了该大小的数组作为输出。
答案 2 :(得分:3)
这是方法参考表达式,请参见JLS 15.13。方法引用的语法为:
MethodReference:
ExpressionName :: [TypeArguments] Identifier
Primary :: [TypeArguments] Identifier
ReferenceType :: [TypeArguments] Identifier
super :: [TypeArguments] Identifier
TypeName . super :: [TypeArguments] Identifier
ClassType :: [TypeArguments] new
ArrayType :: new
您要查看的特定案例是最后一个案例。在您的示例中,String[]
是一个 ArrayType ,这意味着它由一个类型名称以及一个或多个[]
组成。
不应有一个名为String []的类,它非常la脚,我无法解释其实际含义。
请参见上文:它是规格类型,而不是类名。从句法/语言角度看,这种用法类似于:
Class<?> c = String[].class;
或
if (a instanceof String[])
甚至
public void myMethod(String[] arg)
(您不会称呼那些“ lam子”……对吗?)
现在,您可能有一个有效的案例,可以使用这样的new
关键字,从语法上来说意外(尤其是Java 8之前的程序员)。但是,这种意想不到的语法是强烈的要求的结果,即当向Java添加新的语言功能时,设计人员必须不破坏向后兼容性。这并不是完全不直观的。 (当时我不这么认为。当我第一次看到这种结构时,对我来说,这很明显是什么意思。)
现在,如果他们在2018年从头开始,那么Java语言设计的许多细节将变得更加简单和简洁。但是他们没有这样做的奢侈。
答案 3 :(得分:2)
您很容易感到困惑,因为Java在类型与类之间并不是很清楚。
我们知道String[]
是一种类型,因为您可以声明该类型的变量:
jshell> String[] s = new String[]{"Hello", "world"}
s ==> String[2] { "Hello", "world" }
但是,String[]
实际上 被视为Java中的类,而不仅仅是类型:
jshell> s.getClass()
$2 ==> class [Ljava.lang.String;
那个有趣的[Ljava.lang.String
代表“字符串数组”类型出现,以响应getClass
的调用。我同意这是令人惊讶的。但是Java中的每个 object 都必须有一个类,而String[]
是该类。 (在其他语言中,您可能会看到类似Array<String>
之类的字词,但可能会有点破折号。但是Java再进行了类型擦除,因此看起来有些混乱。)
在您的特定情况下,这是正在发生的事情。从流中创建数组时,需要小心类型。天真地,您可能会得到:
jshell> Arrays.asList("a", "b").stream().toArray()
$5 ==> Object[2] { "a", "b" }
所以我们需要version of toArray
that gives us an array:
jshell> Arrays.asList("a", "b").stream().toArray((n) -> new String[n])
$7 ==> String[2] { "a", "b" }
那更好!结果类型是一个字符串数组,而不只是对象数组。现在(n)->new String[n]
可以替换为构造方法参考。 Java允许在方法引用中使用数组类型!所以我们可以这样写:
jshell> Arrays.asList("a", "b").stream().toArray(String[]::new)
$8 ==> String[2] { "a", "b" }
此外:在像这样的方法引用中使用数组类型时,有一些警告,例如要求数组类型必须是可验证的,但我认为这超出了您可能一直在问的范围。这里的TL; DR是,根据设计,Java允许使用::new
在(类似构造函数的)方法引用中使用数组类型。