Java 8 streams demo part 2: Stream of custom objects

11 07 2015

Following 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 to get the idea of this one faster.

Introduction

Now I want to have a list of Users. User is a POJO having a name and age. I am going to filter out users younger than 18 years and sort them in list by their age, ascending. At the beginning I have a list of users:

List<User> users = new ArrayList<User>();
users.add(new User("John", 21));
users.add(new User("Jack", 13));
users.add(new User("Joe", 56));
users.add(new User("Michelle", 37));

Filtering and sorting stream
I convert the list to the stream with the stream() method, filter and sort items. Item is now the User class instance, so I can call its instance methods like getAge().

users.stream()
        .filter(item -> item.getAge() > 18)
        .sorted((item1, item2) -> (item1.getAge() - item2.getAge()))
        .forEach(System.out::println);

Result
As a result I get adult users, sorted by age:

User{name='John', age=21}
User{name='Michelle', age=37}
User{name='Joe', age=56}

Source Code

Find the source Code for this tutorial on my github: https://github.com/yacekmm/Java8Streams/tree/StreamWithObject

Advertisements




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





Android: Action listener on EditText change

8 09 2012

If business logic requires to trigger any kind of action right after the user changes text in EditText View, the TextWatcher listener can be used. Good example of use is filter, that updates when user provides filtering criteria.

Add textChanged listener to EditText:

myEditText.addTextChangedListener(onSearchFieldTextChanged);

Implement listener to perform desired actions:

TextWatcher onSearchFieldTextChanged = new TextWatcher(){
	public void afterTextChanged(Editable s) {
		//your business logic after text is changed
	}
	public void beforeTextChanged(CharSequence s, int start, int count, int after){
		//your business logic before text is changed
	}

	public void onTextChanged(CharSequence s, int start, int before, int count){
		//your business logic while text has changed
	}
};

Did I help you?
I manage this blog and share my knowledge for free sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!








%d bloggers like this: