I second that `Stream.append` would be a very useful addition, although I would definitely propose it as Stream<T> append(Stream<? extends T> other) -> Stream.concat(this, other);
Of course, we could also have a convenience overload like Stream<T> append(T... values) -> append(Arrays.stream(values)); but I do not find it nearly as important. As for `Stream.prepend`, I find it quite non-intuitive because of the flow inversion. For example, I *much* prefer var remainingStream = list.stream() .filter(...) .map(...); Stream.of(specialElement).append(remainingStream).collect(toList()); to list.stream() .filter(...) .map(...) .prepend(specialElement) .collect(toList()); even though the latter is shorter and it's a single expression. Also, note how Stream.of(specialElement).append(remainingStream).collect(toList()); has better "flow" than Stream.concat(Stream.of(specialElement), remainingStream).collect(toList()); Regards, Tomasz Linkowski On Mon, Oct 15, 2018 at 4:51 AM Tagir Valeev <amae...@gmail.com> wrote: > Hello! > > Still from the practical point of view it would be really helpful to > have instance methods like `Stream.append(T... elements)` and > `Stream.prepend(T... elements)` (default implementation may utilize > `concat`). Very often it's necessary to add one or two special > elements to the stream, and using the `concat` makes code very ugly. > > C.f.: > > > list.stream().filter(...).map(...).append(specialElement).collect(toList()); > v.s.: > Stream.concat(list.stream().filter(...).map(...), > Stream.of(specialElement)).collect(toList()); > > Currently I prefer this (unless I can use third-party libraries which > provide `append`): > List<T> result = list.stream().filter(...).map(...).collect(toList()); > // toCollection(ArrayList::new) for purists > result.add(specialElement); > > With best regards, > Tagir Valeev. > On Thu, Oct 11, 2018 at 11:11 PM Brian Goetz <brian.go...@oracle.com> > wrote: > > > > It would surely be convenient; I've wished for this a few times. But, > > there's a reason for this choice, and its not just laziness; > > contravariant type variables have some pretty scary challenges. See, for > > example, this paper: > > > > http://www.cis.upenn.edu/~bcpierce/papers/variance.pdf > > > > in which it is shown that contravariance is one of the ingredients in a > > witches brew that leads to undecideability of type checking. > > > > > > > > On 10/11/2018 12:06 AM, James Roper wrote: > > > With the work I'm doing at the moment at creating a Reactive Streams > > > equivalent to java.util.stream, I've often wondered why Stream.concat > is a > > > static method, rather than an instance method concating the given > stream > > > onto this. But I think the reason has just dawned on me, and I wanted > to > > > confirm that I'm correct. > > > > > > Java doesn't support contravariant type variables - it does for type > > > declarations, but not type variables. > > > > > > To put more concretely, if I had a Stream<Integer>, and I wanted to > concat > > > a Stream<Number>, this is a valid thing to do, the resulting stream > would > > > be Stream<Number>. But doing that with an instance method would require > > > something like this: > > > > > > public <S super T> Stream<S> concat(Stream<? extends S> b); > > > > > > Which is not supported (specifically, <S super T> type variable > declaration > > > is not supported). In contrast, what we have in the actual API: > > > > > > public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? > extends > > > T> b); > > > > > > does allow me to concat a Stream<Integer> and Stream<Number> with a > > > resulting type of Stream<Number>. > > > > > > Is this right, or are there other reasons? Also, is there any > possibility > > > that Java might support contravariance in type variables in future? My > > > reason for wanting it is to provide the following method for reactive > > > streams: > > > > > > public <S super T> Publisher<S> onErrorResumeWith(Function<? super > > > Throwable, ? extends Publisher<? extends S>> f); > > > > > > The intent of this method is when a stream encounters an error, the > passed > > > function is invoked with the error, and that function returns a > publisher > > > that gets concated to the current stream instead of the error being > > > emitted. This could possibly be implemented with a static method: > > > > > > public static <T> Publisher<T> onErrorResumeWith(Publisher<? extends > T> a, > > > Function<? super Throwable, ? extends Publisher<? extends T> f); > > > > > > But unlike concat, this method feels and reads much better as an > instance > > > method, as a static method it's a little confusing. > > > > > > Regards, > > > > > > James > > > > > > -- Pozdrawiam, Tomasz Linkowski