Elo*_*ryx 9 java java-8 method-reference
我已经在Java 8中使用lambdas和方法引用了一段时间,有一件事我不明白.这是示例代码:
Set<Integer> first = Collections.singleton(1);
Set<Integer> second = Collections.singleton(2);
Set<Integer> third = Collections.singleton(3);
Stream.of(first, second, third)
.flatMap(Collection::stream)
.map(String::valueOf)
.forEach(System.out::println);
Stream.of(first, second, third)
.flatMap(Set::stream)
.map(String::valueOf)
.forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)
两个流管道做同样的事情,他们打印出三个数字,每行一个.不同之处在于它们的第二行,似乎只要它具有方法就可以简单地替换继承层次结构中的类名(Collection接口具有默认方法"stream",而未在Set接口中重新定义).我尝试了如果使用这些类一次又一次地重新定义方法会发生什么:
private static class CustomHashSet<E> extends HashSet<E> {
@Override
public Stream<E> stream() {
System.out.println("Changed method!");
return StreamSupport.stream(spliterator(), false);
}
}
private static class CustomCustomHashSet<E> extends CustomHashSet<E> {
@Override
public Stream<E> stream() {
System.out.println("Changed method again!");
return StreamSupport.stream(spliterator(), false);
}
}
Run Code Online (Sandbox Code Playgroud)
在更改第一,第二和第三个赋值以使用这些类之后,我可以替换方法引用(CustomCustomHashSet :: stream),并且毫不奇怪它们在所有情况下都打印出调试消息,即使我使用Collection :: stream也是如此.看来你不能用方法引用调用super,overriden方法.
运行时间有差异吗?什么是更好的做法,请参考顶级接口/类或使用具体的已知类型(Set)?谢谢!
编辑:为了清楚,我知道继承和LSP,我的困惑与Java 8中方法引用的设计有关.我首先想到的是,在方法引用中更改类会改变行为,它会调用它来自所选类的超级方法,但正如测试所示,它没有任何区别.更改创建的实例类型确实会改变行为.
甚至方法引用也必须遵守方法覆盖的 OOP 原则。否则,代码如下
public static List<String> stringify(List<?> o) {
return o.stream().map(Object::toString).collect(Collectors.toList());
}
Run Code Online (Sandbox Code Playgroud)
不会按预期工作。
至于用于方法引用的类名:我更喜欢使用声明方法的最通用的类或接口。
原因是:您编写方法来处理Set. 稍后您会发现您的方法可能对 的集合也很有用Collection,因此您可以相应地更改您的方法签名。现在,如果方法中的代码始终引用 Set 方法,则您也必须调整这些方法引用:
从
public static <T> void test(Collection<Set<T>> data) {
data.stream().flatMap(Set::stream).forEach(e -> System.out.println(e));
}
Run Code Online (Sandbox Code Playgroud)
到
public static <T> void test(Collection<Collection<T>> data) {
data.stream().flatMap(Collection::stream).forEach(e -> System.out.println(e));
}
Run Code Online (Sandbox Code Playgroud)
您也需要更改方法主体,而如果您将方法编写为
public static <T> void test(Collection<Set<T>> data) {
data.stream().flatMap(Collection::stream).forEach(e -> System.out.println(e));
}
Run Code Online (Sandbox Code Playgroud)
您不必更改方法主体。
| 归档时间: |
|
| 查看次数: |
1641 次 |
| 最近记录: |