String [] :: new(或)Byte [] :: new是什么意思?

时间:2019-05-25 18:53:48

标签: java java-8

从java8文档中我可以看到::new用于引用构造函数方法。

但是当涉及到此声明时,

stream.toArray(String[]::new) 

String[]::new是什么意思?不应有一个名为String[]的类,它非常la脚,我无法解释其实际含义。

4 个答案:

答案 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在(类似构造函数的)方法引用中使用数组类型。