简体   繁体   English

为什么许多Java Stream接口方法在参数中使用较低的有界通配符而不是泛型类型?

[英]Why many Java Stream interface methods use lower bounded wildcard in parameters instead of generic type?

Many Java Stream interface methods use lower bounded wildcard in parameters 许多Java Stream接口方法在参数中使用较低的有界通配符

for example 例如

Stream<T> filter(Predicate<? super T> pred)

and

void forEach(Consumer<? super T> action)

What is the advantage of using Predicate<? super T> 使用Predicate<? super T>什么好处Predicate<? super T> Predicate<? super T> over Predicate<T> here? Predicate<? super T> over Predicate<T>在这里?

I understand, with Predicate<? super T> 我理解, Predicate<? super T> Predicate<? super T> as parameter, Predicate object of T and super types can be passed into the method but i can't think of a situation where a Predicate of super type needed over the specific type? Predicate<? super T>作为参数,T和超类型的Predicate对象可以传递给方法,但是我不能想到超类型的Predicate需要超过特定类型的情况?

For example if i have a Stream<Integer> i can pass Predicate<Integer>, Predicate<Number>, and Predicate<Object> objects as arguments to its filter method but why would anyone pass a Predicate<Object> over Predicate<Integer> ? 例如,如果我有一个Stream<Integer>我可以将Predicate<Integer>, Predicate<Number>, and Predicate<Object>对象作为其过滤方法的参数传递,但为什么有人会通过Predicate<Integer>传递Predicate<Object> Predicate<Integer>

What is the advantage of using <? super T> 使用<? super T>什么好处<? super T> <? super T> here? <? super T>在这?

I assume you are aware of the PECS pattern, which is useful to adhere to when designing an API, even if no actual use case jumps into your eye. 我假设您了解PECS模式,这在设计API时非常有用,即使没有实际的用例会突然出现。 When we look at the final state of Java 8 and typical use cases, it's tempting to think that this was not needed anymore. 当我们查看Java 8的最终状态和典型用例时,很容易认为不再需要它了。 Not only do lambda expressions and method references infer the target type even when actually using a more general type, the improved type inference applies to method invocations as well. 即使实际使用更通用的类型,lambda表达式和方法引用不仅会推断目标类型,而且改进的类型推断也适用于方法调用。 Eg 例如

Stream.of("a", "b", "c").filter(Predicate.isEqual("b"));

would require the filter(Predicate<? super T>) declaration with a pre-Java 8 compiler, as it would infer Predicate<Object> for the expression Predicate.isEqual("b") . 需要使用pre-Java 8编译器的filter(Predicate<? super T>)声明,因为它会推断Predicate<Object>表达式Predicate.isEqual("b") But with Java 8, it would also work with Predicate<T> as parameter type, as the target type is used for nested method invocations as well. 但是对于Java 8,它也可以使用Predicate<T>作为参数类型,因为目标类型也用于嵌套方法调用。

We may consider that the development of the Stream API and the new Java language version/ compiler implementation happened at the same time, so there might have been a practical reason to use the PECS pattern at the beginning, while there never was a reason not to use that pattern. 我们可能会认为Stream API的开发和新的Java语言版本/编译器实现同时发生,因此可能有一个实际的理由在开始时使用PECS模式,而从来没有理由不使用那种模式。 It still raises the flexibility when it comes to reusing existing predicate, function or consumer instances and even if that might not be much common, it doesn't hurt. 在重用现有的谓词,函数或消费者实例时,它仍然提高了灵活性,即使这可能不是很常见,也不会造成伤害。

Note that while, eg Stream.of(10, 12.5).filter(n -> n.doubleValue() >= 10) , works, because the predicate may get an inferred non-denotable type suitable to process the Stream's element type “ #1 extends Number & Comparable<#1> ”, you can not declare a variable of that type. 请注意,虽然例如Stream.of(10, 12.5).filter(n -> n.doubleValue() >= 10) ,但是,因为谓词可能得到一个适合处理Stream的元素类型的推断的非可表示类型“ #1 extends Number & Comparable<#1> “,您不能声明该类型的变量。 If you want to store the predicate in a variable, you have to use, eg 如果要将谓词存储在变量中,则必须使用,例如

Predicate<Number> name = n -> n.doubleValue()>=10;
Stream.of(10, 12.5).filter(name);

which only works, if filter has been declared as filter(Predicate<? super T> predicate) . 如果filter已声明为filter(Predicate<? super T> predicate) ,则只能起作用。 Or you enforce a different element type for the Stream, 或者您为Stream强制使用不同的元素类型,

Predicate<Number> name = n -> n.doubleValue()>=10;
Stream.<Number>of(10, 12.5).filter(name);

which already demonstrates how omitting the ? super 哪个已经演示了如何省略? super ? super at the filter declaration may cause more verbosity on the caller's side. filter声明中的? super可能会导致调用方更加冗长。 Also, enforcing a more general element type may not be an option if the more specific type is needed in a later pipeline stage. 此外,如果在以后的管道阶段中需要更具体的类型,则强制执行更通用的元素类型可能不是一种选择。

While existing function implementations are rare, there are some, eg 虽然现有的功能实现很少见,但有一些例如

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();

wouldn't work without the ? super 如果没有? super ? super in the forEach(Consumer<? super T> action) declaration. ? superforEach(Consumer<? super T> action)声明中。

A case you may encounter more often, is to have an existing Comparator implementation which you might want to pass to a sorted method of a Stream with a more specific element type, eg, 您可能经常遇到的情况是,您可能希望将现有的Comparator实现传递给具有更具体元素类型的Stream的已sorted方法,例如,

Stream.of("FOO", "bar", "Baz")
      .sorted(Collator.getInstance())
      .forEachOrdered(System.out::println);

wouldn't work without the ? super 如果没有? super ? super in the sorted(Comparator<? super T> comparator) declaration. ? super sorted(Comparator<? super T> comparator)声明。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM