xsh*_*he2 7 java java-8 java-stream method-reference
我正在学习如何使用流,我遇到了这个方法的问题.
public static String[] inArray(String[] array1, String[] array2) {
return Arrays.stream(array1)
.filter(str -> Arrays.stream(array2).anyMatch(s -> s.contains(str)))
.distinct().sorted().toArray(**String[]::new**);
}
Run Code Online (Sandbox Code Playgroud)
我很困惑String[]::new,你能给我一个暗示吗?
And*_*lko 11
String[]::new手段size -> new String[size].
当Stream#toArray(IntFunction<A[]> generator)准备生成数组时,它调用generator并传递generator.apply内部集合的大小以获取集合以填充它.
Nam*_*man 10
我想说现有的答案提供了一些见解,但还没有一个讨论IntFunction<R>。
补充一下,它在上下文中的含义Stream.toArray(String[]::new)是它代表一个IntFunction实现,例如:
new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
}
Run Code Online (Sandbox Code Playgroud)
其中代码创建新分配String[]的大小value并生成该大小的数组作为输出。
您感到困惑是正确的,因为 Java 对于类型与类并不是非常清楚。
我们知道这String[]是一种类型,因为您可以声明该类型的变量:
jshell> String[] s = new String[]{"Hello", "world"}
s ==> String[2] { "Hello", "world" }
Run Code Online (Sandbox Code Playgroud)
然而,String[]实际上在 Java 中被视为一个类,而不仅仅是一个类型:
jshell> s.getClass()
$2 ==> class [Ljava.lang.String;
Run Code Online (Sandbox Code Playgroud)
[Ljava.lang.String代表“字符串数组”类型的那个看起来很有趣的会在getClass响应调用时出现。我同意这令人惊讶。但是Java中的每个对象都必须有一个类,并且String[]就是那个类。(在其他语言中,您可能会看到类似的内容Array<String>,这可能会更清晰。但是 Java 具有类型擦除功能,因此,事情看起来有点令人困惑。)
在您的具体情况下,这就是发生的情况。从流创建数组时需要小心类型。天真地,你可能会得到:
jshell> Arrays.asList("a", "b").stream().toArray()
$5 ==> Object[2] { "a", "b" }
Run Code Online (Sandbox Code Playgroud)
所以我们想要给我们一个数组的版本toArray:
jshell> Arrays.asList("a", "b").stream().toArray((n) -> new String[n])
$7 ==> String[2] { "a", "b" }
Run Code Online (Sandbox Code Playgroud)
这样更好!结果类型是字符串数组,而不仅仅是对象数组。现在(n)->new String[n]可以用构造方法参考来代替。Java允许在方法引用中使用数组类型!所以我们可以写:
jshell> Arrays.asList("a", "b").stream().toArray(String[]::new)
$8 ==> String[2] { "a", "b" }
Run Code Online (Sandbox Code Playgroud)
另外:在像这样的方法引用中使用数组类型时有一些注意事项,例如要求数组类型必须是可具体化的,但我认为这有点超出了您可能要求的范围。这里的 TL;DR 是,根据设计,Java 允许在(类似构造函数)方法引用中使用::new.
这是一个方法引用表达式,请参阅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
Run Code Online (Sandbox Code Playgroud)
您正在查看的具体案例是最后一个。在您的示例中,String[]是ArrayType,这意味着它由类型名称后跟一个或多个[].
不应该有一个名为 String[] 的类,它非常蹩脚,我无法解释它的实际含义。
参见上文:它是类型规范而不是类名。从句法/语言学的角度来看,这种用法类似于:
Class<?> c = String[].class;
Run Code Online (Sandbox Code Playgroud)
或者
if (a instanceof String[])
Run Code Online (Sandbox Code Playgroud)
甚至
public void myMethod(String[] arg)
Run Code Online (Sandbox Code Playgroud)
(你不会称这些为“蹩脚”......你会吗?)
现在您可以有一个有效的案例来说明能够使用这样的关键字在语法上是意外的(尤其是对于 Java 8 之前的程序员)。new但这种意想不到的语法是设计者在向 Java 添加新语言功能时不得破坏向后兼容性的强烈要求的结果。这并非不直观。(至少,我不这么认为。当我第一次看到这个构造时,我很清楚它的含义。)
现在,如果他们在 2018 年从头开始,Java 语言设计的很多细节都会变得更简单、更清晰。但他们没有这样做的奢侈。
mel*_*182 -2
要将流转换为另一个列表,您可以使用:
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)