为什么许多Java Stream接口方法在参数中使用较低的有界通配符而不是泛型类型? [英] Why many Java Stream interface methods use lower bounded wildcard in parameters instead of generic type?

查看:79
本文介绍了为什么许多Java Stream接口方法在参数中使用较低的有界通配符而不是泛型类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

许多Java Stream接口方法在参数中使用较低的有界通配符

Many Java Stream interface methods use lower bounded wildcard in parameters

例如

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

void forEach(Consumer<? super T> action)

使用 Predicate< ;?有什么好处?超级T> 超过谓词< T> 这里?

据我所知,谓词< ;?超级T> 作为参数,T和超类型的Predicate对象可以传递给方法,但我想不出超特定类型的Predicate需要超过特定类型的情况?


例如,如果我有一个 Stream< Integer> 我可以传递 Predicate< Integer>,Predicate< Number> ;和谓词< Object> 对象作为其过滤方法的参数,但为什么有人会在 Predicate< Object> >谓词<整数> ?

使用< ;?有什么好处?超级T> 这里?

I understand, with 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?

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>?

What is the advantage of using <? super T> here?

推荐答案

我假设你知道 PECS 模式,在设计API时很有用,即使没有实际的用例也会突然出现。当我们查看Java 8的最终状态和典型用例时,很容易认为不再需要它了。即使实际使用更通用的类型,lambda表达式和方法引用不仅会推断目标类型,而且改进的类型推断也适用于方法调用。例如

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. 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. 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. E.g.

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

需要过滤器(Predicate<?super T>)使用Java 8之前的编译器进行声明,因为它会推断 Predicate< Object> 表达式 Predicate.isEqual(b )。但是使用Java 8,它也可以作为参数类型与 Predicate< T> 一起使用,因为目标类型也用于嵌套方法调用。

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"). 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.

我们可能会认为Stream API的开发和新的Java语言版本/编译器实现同时发生,因此可能有一个实际的理由在开始时使用PECS模式虽然没有理由不使用这种模式。在重用现有的谓词,函数或消费者实例时,它仍然提高了灵活性,即使这可能不常见,也没有什么坏处。

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. 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.

注意而,例如 Stream.of(10,12.5).filter(n - > n.doubleValue()> = 10),有效,因为谓词可能会得到推断的非可表示的类型适合处理Stream的元素类型#1 extends Number&可比较<#1> ,您无法声明该类型的变量。如果要将谓词存储在变量中,则必须使用,例如。

Note that while, e.g. 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. If you want to store the predicate in a variable, you have to use, e.g.

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

只有在过滤器的情况下才有效声明为过滤器(Predicate<?super T>谓词)
或者您为Stream强制使用不同的元素类型,

which only works, if filter has been declared as filter(Predicate<? super T> predicate). Or you enforce a different element type for the Stream,

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

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

which already demonstrates how omitting the ? super at the filter declaration may cause more verbosity on the caller’s side. 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, e.g.

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

如果没有

是行不通的? forEach(消费者<?超级T>操作)声明中的超级

wouldn’t work without the ? super in the forEach(Consumer<? super T> action) declaration.

您可能经常遇到的情况是,您可能希望传递给已排序具有更具体元素类型的Stream的方法,例如

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, e.g,

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

如果没有

是行不通的?超级排序(比较器<?超级T>比较器)声明。

这篇关于为什么许多Java Stream接口方法在参数中使用较低的有界通配符而不是泛型类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆