java - 为什么很多 Java Stream 接口(interface)方法在参数中使用下界通配符而不是泛型类型?

标签 java generics java-stream

许多 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);

这已经演示了如何省略 ? superfilter声明可能会导致调用方更加冗长。此外,如果在稍后的管道阶段需要更具体的类型,则强制执行更通用的元素类型可能不是一种选择。

虽然现有的功能实现很少见,但还是有一些,例如

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/

相关文章:

java - 填充所有状态值的摘要计数

java - 我在扫描字符串时遇到问题

java - build-wsdl2java.xml 是如何生成的?

java - 从映射表中获取一个查询中的数据

C# 泛型约束

java - Java 中的 "A Map of Class<?> to List<The class>"怎么说?

java - Paypal api 调用 adaptiveAccountsService createAccount 获取 “MissingCredentialException”

c# - 将对象转换为通用列表

java - 如何使用 Java 流优雅地找到一个数字的质因数?

java - 使用 Stream 从 int[] 数组中查找奇数