Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 - stream ideology

I have recently started playing with Java 8, having done bits and pieces in Haskell/Scala before. I am trying to play with higher-order functions in Java such as map or forEach, and I am struggling to understand what motivation it was to push everything towards Stream ideology. I understand it gives nice, general abstraction, it is supposed to be lazy, but let's consider a very simple, common example:

list.map(x -> do_sth(x));

very common idiom, expecting this to return a List<T>. Now, in Java 8, I need to do sth of this sort:

list.stream().map(x -> doSth(x)).collect(Collectors.toList())

Now, as far I see this, the stream will not apply the map until collect is called, so there will be one pass through the collection under the hood. What I can't see is why those common use cases for maps, lists such as map.toList(), list.groupBy() would not be added to corresponding interfaces? Is there an underlying design decision I am missing here?

like image 672
Bober02 Avatar asked Feb 06 '14 15:02

Bober02


People also ask

What is Stream in Java 8?

Introduced in Java 8, the Stream API is used to process collections of objects. A stream is a sequence of objects that supports various methods which can be pipelined to produce the desired result.

What are the two types of streams proposed by Java 8?

With Java 8, Collection interface has two methods to generate a Stream. stream() − Returns a sequential stream considering collection as its source. parallelStream() − Returns a parallel Stream considering collection as its source.

When performing operations on a stream will it affect the original stream?

A stream can be composed of multiple functions that create a pipeline that data that flows through. This data cannot be mutated. That is to say the original data structure doesn't change. However the data can be transformed and later stored in another data structure or perhaps consumed by another operation.


Video Answer


1 Answers

A handful of new methods have been added directly to various collections that perform mutative operations eagerly on those collections. For example, to run a function over each element of a list, replacing the original elements with the return values, use List.replaceAll(UnaryOperator). Other examples of this are Collection.removeIf(Predicate), List.sort(), and Map.replaceAll(BiFunction).

By contrast, there are a bunch of new methods added to Stream such as filter, map, skip, limit, sorted, distinct, etc. Most of these are lazy and they do not mutate the source, instead passing elements downstream. We did consider adding these directly to the collections classes. At this point several questions arose. How do we distinguish the eager, mutative operations from the lazy, stream-producting operations? Overloading is difficult, because they'd have different return types, so they'd have to have different names. How would such operations be chained? The eager operations would have to generate collections to store intermediate results, which is potentially quite expensive. The resulting collections API would have a confusing mixture of eager, mutative and lazy, non-mutating methods.

A second order consideration is potential incompatibilities with adding default methods. The biggest risk with adding default methods to an interface is a name clash with an existing method on an implementation of that interface. If a method with the same name and arguments (often no arguments) has a different return type, that's an unavoidable incompatibility. For that reason we've been fairly reluctant to add large numbers of default methods.

For these reasons, we decided to keep the lazy, non-mutating methods all within the stream API, at the expense of requiring extra method calls stream() and collect() to bridge between collections and streams. For a few common cases we added eager, mutating calls directly to the collections interfaces, such as those I listed above.

See lambdafaq.org for further discussion.

like image 67
Stuart Marks Avatar answered Sep 28 '22 06:09

Stuart Marks