为什么Java中没有实例级的Stream.concat方法?

scu*_*bbo 12 java java-8 java-stream

我知道Stream.concat存在(doc)来连接两个流.但是,我遇到了需要在现有流中添加"更多"项目,然后继续处理它的情况.在这种情况下,我本来希望能够将以下方法联系在一起:

getStream(someArg)
  .map(Arg::getFoo)
  .concat(someOtherStreamOfFoos) // Or append, or...
  .map(...)
Run Code Online (Sandbox Code Playgroud)

但是,不存在这种实例级可链接append/concat方法.

这不是一个问题,要求解决这个问题,或更优雅的方法(虽然我当然会感激任何其他观点!).相反,我问的是导致这一决定的设计因素.我相信,Stream界面是由一些非常聪明的人设计的,他们都知道最小惊讶原则 - 所以,我必须假设他们决定省略这个(对我来说)直观明显的方法,这意味着该方法是一个反模式,或由于某些技术限制而无法实现.我很想知道原因.

use*_*ica 11

我可以给你一个不起作用的理由.

Stream.concat 被定义为

static <T> Stream<T> concat(Stream<? extends T> a,
                            Stream<? extends T> b)
Run Code Online (Sandbox Code Playgroud)

你可以concatStream<HashMap>Stream<Map>Stream<Map>,甚至concatStream<HashMap>Stream<TreeMap>Stream<Map>.要使用实例方法执行此操作,您需要能够声明类型参数<U super T>,例如Java不允许的类型参数.

// It'd look kind of like this, if Java allowed it.
public <U super T> Stream<U> concat(Stream<? extends U> other)
Run Code Online (Sandbox Code Playgroud)

Java只允许上限类型参数,而不是下限.

连接a Stream<Something>和a Stream<SomethingElse>可能看起来很不寻常,但类型推断通常会产生类型参数,这些参数对于使用实例方法来说太具体了.例如,

Stream.concat(Stream.of(dog), animalStream)
Run Code Online (Sandbox Code Playgroud)

如果写成,则需要显式类型参数

Stream.<Animal>of(dog).concat(animalStream)
Run Code Online (Sandbox Code Playgroud)

  • 我认为返回相同的泛型类型在大多数情况下仍然有用,例如当两个流具有相同的类型时.对于极少数情况,他们可以保留不太方便的静态版本.此外,对于任何想知道_why_` <U super T>`是无效Java的人,请参阅:/sf/answers/2372682931/ (3认同)
  • 这是事实,但在实践中它并不重要.如果签名是`Stream <T> concat(Stream <?extends T> other)`,那对大多数情况来说都没问题.对于极少数情况,当你真的想要连接`Stream <Integer>`和`Stream <Double>`时,你可以完成`integerStream.map(a - >(Number)a).concat(doubleStream)` (3认同)
  • 如果我没有弄错,可以使用https://bugs.openjdk.java.net/browse/JDK-8140283中描述的链接方法吗?然后它会减轻可读性问题. (2认同)