Core Java

To Infinity (Streams) and Beyond!

Java allows you to process data in collections or streams. It’s very easy to think of streams as a technique to turn one collection into another. This can lead to some rather casual code where streaming data is repeatedly collected to some sort of collection, passed as a whole collection, and then processed some more.

For 6 elements, who cares!

Example:

01
02
03
04
05
06
07
08
09
10
11
// imaginary input
List<String> list = asList("Foo", "Bar", "Baz");
 
// conversion and sending
List<String> bs = list.stream()
    .filter(item -> item.startsWith("B"))
    .collect(toList());
List<Wrapped> wrapped = bs.stream()
    .map(Wrapped::new)
    .collect(toList());
sendWrappedItems(wrapped.stream());

The above suffers from a code-smell, which is the constant collection and restreaming of a stream, and most people would probably notice that and remove some of the interim lists if it was all one method.

Most people would. I’ve seen people not do this.

However, if the above were using subroutines to process things, it’s quite easy to optimise the simplicity of the subroutines’ APIs and make them receive and return a collection. This was you can end up with the above behaviour.

The solution is to look at the pipeline of data processing at the high level in terms of filter, map, and reduce type functions and try to model it around streams.

But Why?

Treat Streams as Though They’re Infinite

We have small containers these days and we want them to get the most of their resources. A small container, if running continuously can process an unbounded stream of data. If we imagine that all our data is a potentially infinite stream, and design our software to use streaming to avoid getting all of it into memory, then two good things happen:

  • We optimise the max memory requirement of our streams to be as low as possible for ALL cases
  • We HAVE to use the Streaming API properly and we end up with cleaner code, as the declarative aspect of the Stream API helps describe what’s happening in the data conversion. We probably even lost some horribly named temporary variables in the process…

The above code then becomes:

1
2
3
4
5
6
7
// imaginary input
List<String> list = asList("Foo", "Bar", "Baz");
 
// conversion and sending
sendWrappedItems(list.stream()
    .filter(item -> item.startsWith("B"))
    .map(Wrapped::new));

Published on Java Code Geeks with permission by Ashley Frieze, partner at our JCG program. See the original article here: To Infinity (Streams) and Beyond!

Opinions expressed by Java Code Geeks contributors are their own.

Ashley Frieze

Software developer, stand-up comedian, musician, writer, jolly big cheer-monkey, skeptical thinker, Doctor Who fan, lover of fine sounds
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button