许多 Java Stream 接口(interface)方法在参数中使用下界通配符
例如
Stream<T> filter(Predicate<? super T> pred)
和
void forEach(Consumer<? super T> action)
使用Predicate<? super T>
有什么好处?在 Predicate<T>
在这里?
我明白了,Predicate<? super T>
作为参数,可以将 T 和父类(super class)型的 Predicate 对象传递到方法中,但我想不出在特定类型上需要父类(super class)型的 Predicate 的情况?
例如,如果我有一个 Stream<Integer>
我可以通过Predicate<Integer>, Predicate<Number>, and Predicate<Object>
对象作为其过滤器方法的参数,但为什么有人会传递 Predicate<Object>
在 Predicate<Integer>
?
使用<? super T>
有什么好处?在这里?
最佳答案
我假设您知道 PECS模式,在设计 API 时坚持使用它很有用,即使没有实际用例跳入您的眼帘。当我们查看 Java 8 的最终状态和典型用例时,很容易认为它不再需要了。不仅 lambda 表达式和方法引用会推断目标类型,即使在实际使用更通用的类型时也是如此,改进的类型推断也适用于方法调用。例如
Stream.of("a", "b", "c").filter(Predicate.isEqual("b"));
需要 filter(Predicate<? super T>)
使用 Java 8 之前的编译器声明,因为它会推断出 Predicate<Object>
对于表达式 Predicate.isEqual("b")
.但是对于 Java 8,它也适用于 Predicate<T>
作为参数类型,因为目标类型也用于嵌套方法调用。
我们可能认为 Stream API 的开发和新的 Java 语言版本/编译器实现是同时发生的,所以一开始使用 PECS 模式可能有实际原因,但从来没有不使用该模式的原因。在重用现有谓词、函数或消费者实例时,它仍然提高了灵 active ,即使这可能不太常见,也没有坏处。
请注意,例如Stream.of(10, 12.5).filter(n -> n.doubleValue() >= 10)
,有效,因为谓词可能会得到一个推断的不可表示类型,适合处理 Stream 的元素类型“#1 extends Number & Comparable<#1>
” ",您不能声明该类型的变量。如果要将谓词存储在变量中,则必须使用,例如
Predicate<Number> name = n -> n.doubleValue()>=10;
Stream.of(10, 12.5).filter(name);
只有在 filter
时才有效已声明为 filter(Predicate<? super T> predicate)
.
或者您为 Stream 强制使用不同的元素类型,
Predicate<Number> name = n -> n.doubleValue()>=10;
Stream.<Number>of(10, 12.5).filter(name);
这已经演示了如何省略 ? super
在 filter
声明可能会导致调用方更加冗长。此外,如果在稍后的管道阶段需要更具体的类型,则强制执行更通用的元素类型可能不是一种选择。
虽然现有的功能实现很少见,但还是有一些,例如
Stream.Builder<Number> b = Stream.builder();
IntStream.range(0, 10).boxed().forEach(b);
LongStream.range(0, 10).boxed().forEach(b);
Stream<Number> s = b.build();
如果没有 ? super
将无法工作在forEach(Consumer<? super T> action)
声明。
您可能更经常遇到的情况是,有一个现有的 Comparator
您可能希望传递给 sorted
的实现具有更具体元素类型的 Stream 方法,例如,
Stream.of("FOO", "bar", "Baz")
.sorted(Collator.getInstance())
.forEachOrdered(System.out::println);
如果没有 ? super
将无法工作在sorted(Comparator<? super T> comparator)
声明。
关于java - 为什么很多 Java Stream 接口(interface)方法在参数中使用下界通配符而不是泛型类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50313830/