Click here to Skip to main content
Click here to Skip to main content

Introduction to Functional Programming in Java 8 – Part Two

, 2 Jul 2014
Rate this:
Please Sign up or sign in to vote.
Welcome to Part Two! To begin this session, let’s start with a return to our HelloWorld example from the last article. Let’s make one more change to the pipeline – how about we get rid of countries that begin with a G: Now it only greets 4 countries. The filter operation keeps item

Welcome to Part Two! To begin this session, let’s start with a return to our HelloWorld example from the last article.

public class HelloWorldConcise
{
        private void doPrint(String str)
        {
                System.out.println(str);
        }

        private String greet(String country)
        {
                return "Hello " + country + "!";
        }

        public void greetCountries()
        {
                List<String> countries = Arrays.asList("France", "India", 
                "China", "USA", "Germany");

                countries.stream().map(this::greet)
                                  .forEach(this::doPrint);
        }

        public static void main(String[] args)
        {
                new HelloWorldConcise().greetCountries();
        }
}

Let’s make one more change to the pipeline – how about we get rid of countries that contain a G:

                countries.stream().filter(country -> country.indexOf('G') == -1)
                                  .map(this::greet).forEach(this::doPrint);

Now it only greets 4 countries. The filter operation keeps items where the filter’s expression evaluates to true, and discards the others. In this case we have another lambda expression which taking the item to be called country checks that it doesn’t contain a G.

This is very useful as we don’t have to alter the original list, or stop work half way to manually remove some items. Note that it’s also very easy to add another element to our pipeline, and still quite readable what’s going on.

As we’ve done before, let’s look at the under the hood at filter. In this case the lambda expression is actually a Predicate. Predicate has a function ‘test’ which we override to perform our check. Here is an inner-class with the filter’s test explicitly written out:

private static class DoesntContainG implements Predicate<String>
{
	@Override
	public boolean test(String str)
	{
		return str.indexOf('G') == -1;
	}
}

We can change the pipeline as follows to use this class:

		countries.stream().filter(new DoesntContainG())
				  .map(this::greet).forEach(this::doPrint);

Instead of the inner class we could add a new function and pass that as we’ve done before:

        private boolean doesntContainG(String str)
        {
	        return str.indexOf('G') == -1;
        }

and then change the pipeline to the very concise:

		countries.stream().filter(this::doesntContainG)
				  .map(this::greet).forEach(this::doPrint);

How readable is that? Take countries, stream them, filter leaving those that do not contain G, map them to a greeting and print them.

Now suppose we need to use a value part of the way along the pipeline. One obvious application is debugging. If we wanted to print the values so far, we couldn’t use a forEach. forEach is a terminal operation, it consumes all the items and so no operation can follow it. Instead the operation peek is what we need.

Let’s see Germany being removed. We’ll add the following function:

private void check(String country)
{
	System.out.println("Found " + country);
}

and change the pipeline as follows:

countries.stream().peek(this::check).filter(this::doesntContainG)
		  .peek(this::check).map(this::greet)
  		  .forEach(this::doPrint);

This will print the countries before and after the filter. Note that Germany is only found once (before the filter), where as all the others are found after as well, so we can conclude that the filter is indeed removing it.

For a preview of what will be covered in a future article, try changing stream() to parallelStream() in the example and see what happens.

So that’s the basic operations we’ve covered so far in the blog. We can take a container make a stream, transform items, filter items, peek at them and do something with them.


Revision History:

2nd July 2014 - Corrected the category

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

TheCannyCoder

United Kingdom United Kingdom
No Biography provided

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 2 Jul 2014
Article Copyright 2014 by TheCannyCoder
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid