Java 8 StringJoiner demo

24 01 2016

Finally Java has convenient and intuitive API for joining strings with delimiters! Since Java 8 there is StringJoiner class. It is an API that you may know from Guava Joiner classes (see my post: https://looksok.wordpress.com/2015/10/17/guava-joiner-join-all-strings-in-an-array-or-map/). Here is a short StringJoiner demo.

Basic String joins

The most basic usage is to create StringJoiner instance with delimiter as a constructor param and add() strings:

StringJoiner joiner = new StringJoiner(",");
joiner.add("apple");
joiner.add("banana");
joiner.add("orange");

System.out.println("Joiner result is: " + joiner.toString());

The result is:

Joiner result is: apple,banana,orange

If you prefer, you can chain add() calls:

StringJoiner joiner = new StringJoiner(",")
    .add("apple")
    .add("banana")
    .add("orange");

Join Collection of Strings

If you have Collection of Strings, the new static String.join() method can join them:

List<String> list = Arrays.asList("apple", "banana", "orange");
String joined = String.join(", ", list);

System.out.println("Join Array result is: " + joined);

With the result of:

Join Array result is: apple, banana, orange

Join inline

You can prepare joined String in one line with String.join() overloaded with varargs, like that:

String.join(", ", "apple", "banana", "orange");

Joining Collector in Stream API

When using streams you have joining Collector at your disposal:

List<String> list = Arrays.asList("apple", "banana", "orange");
String joined = list.stream()
        .collect(Collectors.joining(", "));

System.out.println("Joined with collector: " + joined);

This will result with:

Joined with collector: apple, banana, orange

Source Code

As always, I share with you the source code for this demo on my github: https://github.com/yacekmm/looksok/tree/StringJoinerDemo/Java/JavaDemo

Advertisements




Java 7: Try-With-Resources block that closes the resources for you

28 11 2015

Working with resources (like files stream, byte stream, network stream) in Java requires to close() the resource after you’re done. How often did you forget to close it in your finally block? Even if you didn’t – Java creators proved that 75% of close() implementations got bugs in it. Since Java 7 all resources you use can be automatically closed when try-catch block completes thanks to the new syntax.

Closing resources old-style

You needed to try to close the resource in finally block (and handle the exception if close failed). It looked like that:

InputStream is = null;
try{
	is = url.openStream();
	//read and process the stream
}catch(AllPossibleExceptions){
	//and handle them
}finally{
	try{
		if(is != null)
			is.close();
	}catch(IOException){
		//handle exception on closing the stream
	}
}

Quite a lot of repeatable exception handling and null-avoidance code.

Try With Resources (TWR) Syntax in Java 7

This is how you write resource processing code since Java 7 with improved try()-catch syntax:

try (InputStream is = url.openStream()){
	//read and process the stream
	//stream will be automatically closed for you
}catch(AllPossibleExceptions){
	//and handle them
}

Notice the new try() syntax where you initialize the resource. Stream that is declared there will be automatically closed when the try block execution ends. You can have more Streams initialized there, separated with semicolons.

Why the resource is being closed?

Because it implements AutoClosable interface – the new interface in Java 7. Class must implement that interface to appear in the try() clause. The AutoClosable is a superinterface of the Closable interface (both have only the close() method that closes the resource)

Ceveat

Be aware that nested resources will not be closed. Do not use syntax like that:

try ( ObjectInputStream in = new ObjectInputStream(new 
			FileInputStream("app.properties")) ) {
	//...
}

the issue here is that the inner resource (FileInputStream) will not be closed. If you need constructs like this, where one resource depends on another, then separate their initialization like that:

try ( FileInputStream fileStream = new FileInputStream("app.properties");
	ObjectInputStream in = new ObjectInputStream(fileStream) ) {
	//...
}

then the TWR will work its best for you.





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





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








%d bloggers like this: