Skip to content

Instantly share code, notes, and snippets.

@edalorzo
Created September 14, 2014 19:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save edalorzo/148c6e4f8f0c49d2d5f2 to your computer and use it in GitHub Desktop.
Save edalorzo/148c6e4f8f0c49d2d5f2 to your computer and use it in GitHub Desktop.
Stream Concatenation
public static <T> Stream<T> concatenate(Stream<T>... streams) {
return Stream.of(streams).reduce(Stream.empty(), Stream::concat);
}
public static void main(String[] args) {
Stream<? extends CharSequence> res = concatenate(
Stream.of("One"),
Stream.of(new StringBuffer("Two")),
Stream.of(new StringBuilder("Three"))
);
res.forEach(System.out::println);
}
@kacper-kuczek
Copy link

https://gist.github.com/kacperKant/e7852ef6a6ee4442fec9
Ok, there is one difference that when you put <? extends T> in method signature it leaves client code clearer. Client do not have to specify long <? extends Something> instead simple < Something >. You may say there is no difference but you can treat Stream<? extends Something> only as it contains < Something > so why we shouldn't return it in the first place?

Additionally I vote for your answer on stackoverflow cause it is great. I am writing post on linkedin and I'll put link to your post of the history of Stream.concat method in api. Hope it is ok:)

@edalorzo
Copy link
Author

What you say about the use of wildcards make sense when you want to bound a generic type to a specific bound like T extends Comparable or T extends Serializable.

But the use of ? extends T does not make sense at all in a generic method, since T will replace whatever type you pass already. In other words T is already as flexible as you can get.

My use of ? extends CharSequence was just an example, my code, without the use ? extends T works perfectly for the example you gave:

public static void main(String[] args) {

        Stream<CharSequence> res = concatenate(
                Stream.<CharSequence>of("One"),
                Stream.of(new StringBuffer("Two")),
                Stream.of(new StringBuilder("Three"))
        );

        res.forEach(System.out::println);
    }

@kacper-kuczek
Copy link

Ok it works but thanks to 'target type' of java 8. All of your Streams: "One", "Two", "Three" is exactly Stream< CharSequence >. Also first one might be written as Stream.of("One") and still it work but what if you have already declared Streams eg.:

  Stream<String> f = Stream.of("One");
  Stream<StringBuffer> s = Stream.of(new StringBuffer("Two"));
  Stream<StringBuilder> t = Stream.of(new StringBuilder("Three"));

  Stream<CharSequence> res = concatenate(f, s, t);

My version still work and simple T is not enough.
As you quote Michael Hixson in your original post probably the best implementation of concat would be Stream.of(s1, s2, s3, ...).flatMap(x -> x) or equal Stream.of(s1, s2, s3, ...).flatMap(identity())
Its not that <? extends T> is pointless. It is not! It gives you more flexibility:) Nonetheless maybe there is no point to write a function for concatenation maybe even Stream.concat() is useless cause of idiom: Stream.of(s1, s2, s3, ...).flatMap(identity()) but if you want to put it in method, signature should be precise <? extends T> :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment