Java 8 Streams demo

28 06 2015

Why streams?

Nearly every Java app iterates collections, making operations on its elements, searching, changing them, sorting and so on. Streams are more readable way of doing this. Streams operations are to some excent similar to SQL Query operations – you can select, filter, order items in collection.

What is a stream

Stream is a sequence of elements. This is simply taken – another abstraction for an array or list.

Follow this post to quickly get the idea behind it. Read Oracle article to learn details.

How to get a stream?

As simple as that:

List<String> list = new ArrayList<String>();
Stream<String> stream = list.stream();

What operations can you do on a stream?

Two types:

intermediate operations: they are called on a Stream type, perform requested operations, and return modified stream. So you can call on it next operation working on Stream (pipelining)

terminal operations that are always placed at the end of a pipeline and return array, list or void. Use them if you want to retrieve a list from a stream for example.

Terminal operation example – printing all list items to the console

Having array list like this:

List<String> names = new ArrayList<String>();
names.add("John");
names.add("Jack");
names.add("Joe");
names.add("Michelle");

And using terminal operation forEach on a Stream you can println() each element from the list.

names.stream()
    .forEach(System.out::println);

The System.out.println is referenced by a static reference with a double colon ‘::‘ – good old C-style operator. So you do not call the println() method immediately but pass its reference to the forEach() and it gets called in its time. This is declarative style of coding – you declare what should be called, not when. JVM calls it for you.

The result on a console is:

John
Jack
Joe
Michelle

Filtering example

filter() operation is an intermediate method that takes a stream, filters it with specified condition and returns filtered stream. Let’s say that I need only names with length > 3:

names.stream()
    .filter(item -> item.length() > 3)
    .forEach(System.out::println);

Here the lambda expression is used. For each item the length check is applied and based on a result the item passes the filter or not. More about Lambda expressions you can read in post Lambda Expression example. The result is:

John
Jack
Michelle

Sorting

To sort items use sorted() intermediate operation and pass a comparing statement to it. I sort names according to the length, descending:

names.stream()
    .filter(item -> item.length() > 3)
    .sorted((item1, item2) -> (item2.length() - item1.length()))
    .forEach(System.out::println);

The lambda expression is comparing two items according to Comparable interface return type: return 0 if equal, and less than zero or more than zero if item2 length is more than item1.

The result is a sorted list:

Michelle
John
Jack

Modify items in stream

map() intermetiade operation allows you to modify each item in a stream. Here, I will greet all of names in the list by concatenating the name with a “Hello” string:

names.stream()
    .filter(item -> item.length() > 3)
    .sorted((item1, item2) -> (item2.length() - item1.length()))
    .map(item -> "Hello, " + item)
    .forEach(System.out::println);

The result is:

Hello, Michelle
Hello, John
Hello, Jack

More pipelining

I can accumulate all the intermediate operations. Here I use one more filter() and map() operations:

names.stream()
    .filter(item -> item.length() > 3)
    .filter((item -> item.startsWith("J")))
    .sorted((item1, item2) -> (item2.length() - item1.length()))
    .map(item -> "Hello, " + item)
    .map(item -> item.toUpperCase() + "!")
    .forEach(System.out::println);

To get the result:

HELLO, JOHN!
HELLO, JACK!

Limit the result size

Let’s say that I need only the first item in a result – I can use limit():

names.stream()
    .filter(item -> item.length() > 3)
    .filter((item -> item.startsWith("J")))
    .sorted((item1, item2) -> (item2.length() - item1.length()))
    .map(item -> "Hello, " + item)
    .map(item -> item.toUpperCase() + "!")
    .limit(1)
    .forEach(System.out::println);

And get the result:

HELLO, JOHN!

Terminal operation: get list from a stream

Now if after all of the operations I need a result as a list again, I can use the terminal operation collect() and pass it the toList() operation:

List<String> result = names.stream()
        .filter(item -> item.length() > 3)
        .filter((item -> item.startsWith("J")))
        .sorted((item1, item2) -> (item2.length() - item1.length()))
        .map(item -> "Hello, " + item)
        .map(item -> item.toUpperCase() + "!")
        .limit(1)
        .collect(toList());
        
System.out.println(result);

I will get the result on a console:

[HELLO, JOHN!]

Get the source code

If you wish to download source code for this guide, go to my github: https://github.com/yacekmm/Java8Streams/tree/String

Advertisements

Actions

Information

One response

11 07 2015
Java 8 streams demo part 2: List of custom objects | Looks OK!

[…] the List with primitive types like in post here: Java 8 Streams demo, now it’s time to demonstrate streams with custom objects. Please read mentioned post first […]

Give Your feedback:

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: