4

default Stream<E> stream() is added to Collection interface to support streams in Java 8. Similar functionality is supported by public static<T> Stream<T> of(T t) in Stream class. What different purpose is static of() method solving ?

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
sumit sachdeva
  • 429
  • 3
  • 12
  • 1
    You can create a Stream using varargs and arrays, not possible directly via the Collection-way. – luk2302 May 10 '17 at 08:29

4 Answers4

6

The method stream() of the Collection interface can be called on an existing collection. Being an interface method, it can be overridden by actual collection implementations to return a Stream adapted to the specific collection type.

The standard collections of the JRE don’t take this opportunity, as the default implementation’s strategy of delegating to spliterator(), which is also an overridable method, suits their needs. But the documentation even mentions scenarios in which the collection should override stream():

This method should be overridden when the spliterator() method cannot return a spliterator that is IMMUTABLE, CONCURRENT, or late-binding.


In contrast, the static factory method(s) Stream.of(…) are designed for the case when you have a fixed number of elements without a specific collection. There is no need to create a temporary Collection when all you want is a single Stream over the elements you can enumerate.

Without collections of potentially different type, there is no need for overridable behavior, hence, a static factory method is sufficient.


Note that even if you don’t have a enumerable fixed number of elements, there is an optimized solution for the task of creating a single stream, when no reusable collection is needed:

Stream.Builder<MyType> builder=Stream.builder();
builder.add(A);
if(condition) builder.add(B);
builder.add(C);
builder.build()./* stream operations */
Holger
  • 285,553
  • 42
  • 434
  • 765
  • first, up-vote. but the primary different between `Collection.stream` & `Stream.of` is, the first is applying Template Method Pattern but the second applying Factory Method Pattern. and they are both factory methods. am I right? – holi-java May 10 '17 at 19:13
  • `Collection.stream` may also be considered to fulfill the *abstract factory* pattern (even if there is a default). It’s not unusual to identify more than one pattern in a software. You may confine it by using the term *static factory method* as the name of the pattern behind the `Stream.of` method. I even happened to do that in my answer unconsciously. I usually prefer focusing on the implications of a design rather than the names of the software design pattern. – Holger May 11 '17 at 08:14
  • Thanks. I think your comment is a great answer than any answer. – holi-java May 11 '17 at 12:09
3

As far as I can tell, of is just an utility method to create Streams on the fly, without the need to wrap your elements inside a collection first.

Generally static factory methods as of are provided to skip the array creation because of var-args. For example java-9 immutable collections provide many overloads of these methods like:

 Set.of()
 Set.of(E)
 Set.of(E e1, E e2)
 .... so on until 11
 Set.of(E... elem)

Even the description of those methods is:

While this introduces some clutter in the API, it avoids array allocation, initialization, and garbage collection overhead that is incurred by varargs calls

Since there are only two methods in Stream:

 Stream.of(T t)
 Streamm.of(T ... values)

I consider that small utility methods that can create Streams from var-args.

But they still provide a method that creates a Stream with a single element (instead of leaving just the var-args method), so for a single element this is already optimized.

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • The reason why there are not so many `Stream.of` methods like `Set.of` or `List.of`, is that the latter guaranty to return an immutable collection, hence, can’t just keep a reference to the array which might be shared. In contrast, `Stream.of(T...)` just delegates to the `Arrays.stream`, so the resulting stream will iterate over the array without another copying step. – Holger May 11 '17 at 08:24
2

A interface can add static methods/default methods since jdk-8. and you can see some examples of applying patterns on interface in this question.

First, they are both calling StreamSupport.stream to create a stream.

// Collection.stream()
default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

// Stream.of(E)
public static<T> Stream<T> of(T t) {
    return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
}

stream() added to Collection interface is a good example to applying Template-Method Pattern in interface by default methods. and you can see the source code that stream method call a method spliterator which implements by default in Collection interface.

default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

default Spliterator<E> spliterator() {
    return Spliterators.spliterator(this, 0);
}

AND class derived from Collection can be override spliterator implements different algorithm that will using highest performance algorithm instead. for example spliterator in ArrayList:

public Spliterator<E> spliterator() {
    return new ArrayListSpliterator<>(this, 0, -1, 0);
}

Finally, Stream.of() method is a good example to applying Factory Method in interface by static method. it's a factory method for create a stream from an object instance.

Community
  • 1
  • 1
holi-java
  • 29,655
  • 7
  • 72
  • 83
2

The other answers clearly explain the differences between Collection.stream and Stream.of, when to use one or the other, which design patterns are being applied, etc. @Holger goes even further and shows a sample usage of Stream.Builder, which I think is highly under-used.

Here I want to complement the other answers by showing a mixed usage of both Stream.of and Collection.stream methods. I hope that this example would be clear enough to show that even if both Stream.of and Collection.stream are completely different methods, they can also be used together to fulfil a more complex requirement.

Suppose you have N lists, all of them containing elements of the same type:

List<A> list1 = ...;
List<A> list2 = ...;
...
List<A> listN = ...;

And you want to create one stream with the elements of all lists.

You could create a new empty list and add the elements of all the lists into this new list:

int newListSize = list1.size() + list2.size() + ... + listN.size();
List<A> newList = new ArrayList<>(newListSize);

newList.addAll(list1);
newList.addAll(list2);
...
newList.addAll(listN);

Then, you could call stream() on this list and you would be done:

Stream<A> stream = newList.stream();

However, you would be creating an intermediate, pointless list, with the sole purpose of streaming the elements of the original list1, list2, ..., listN lists.

A much better approach is to use Stream.of:

Stream<A> stream = Stream.of(list1, list2, ..., listN)
    .flatMap(Collection::stream);

This first creates a stream of lists by enumerating each one of them and then flat-maps this stream of lists into a stream of all lists' elements by means of the Stream.flatMap operation. Thus, Collection.stream is called when flat-mapping the original stream.

fps
  • 33,623
  • 8
  • 55
  • 110
  • first, up-vote. a good practice for combine Collection streams. but you can also using `Stream.concat(...streams)`. – holi-java May 11 '17 at 14:40
  • 1
    after thinking. I think your way is pretty way do that. good jobs. and writing a composing method is unnecessary. and duplicate logic with `Stream.of(...Collection).flatMap(Collection::stream)` – holi-java May 11 '17 at 14:49