Java 8 lambda walkthrough

For work I have made a presentation about Java 8 project lambda and of course also some simple code illustrating some of the points. The overall reasons for Java 8 are:

  • More concise code (for classes that have just one method & collections). “We want the reader of the code to have to wade through as little syntax as possible before arriving at the “meat” of the lambda expression.” – Brian Goetz (http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-4.html)
  • Ability to pass around functionality, not just data
  • Better support for multi core processing

All examples are runnable on the following version of Java 8 downloaded from here:

openjdk version "1.8.0-ea"
OpenJDK Runtime Environment (build 1.8.0-ea-lambda-nightly-h3876-20130403-b84-b00)
OpenJDK 64-Bit Server VM (build 25.0-b21, mixed mode)

The simplest case:

public class ThreadA {

    public static void main(String[] args) {

        new Thread(new Runnable() {

            @Override
            public void run() {
                System.err.println("Hello from anonymous class");
            }
        }).start();

    }

}
public class ThreadB {

    public static void main(String[] args) {
        new Thread(() -> {
            System.err.println("Hello from lambda");
        }).start();

    }

}

Note the syntax, informally as

()|x|(x,..,z) -> expr|stmt

The arrow is a new operator. And note the conciseness of the second piece of code compared to the more bulky first piece.

Collections:

First let me introduce an simple domain and some helpers

public class Something {

    private double amount;

    public Something(double amount) {
        this.amount = amount;
    }

    public double getAmount() {
        return amount;
    }

    public String toString() {
        return "Amount: " + amount;
    }
}

public class Helper {

    public static List<Something> someThings() {
        List<Something> things = new ArrayList<>();
        things.add(new Something(99.9));
        things.add(new Something(199.9));
        things.add(new Something(299.9));
        things.add(new Something(399.9));
        things.add(new Something(1199.9));
        return things;
    }

}

public interface Doer<T> {

    void doSomething(T t);

}

Lets do some filtering and sorting Java 7 style:

public class CollectionA {

    public static void main(String... args) {

        List<Something> things = Helper.someThings();

        System.err.println("Filter");
        List<Something> filtered = filter(things);
        System.err.println(filtered);

        System.err.println("Sum");
        double sum = sum(filtered);
        System.err.println(sum);

    }

    public static List<Something> filter(List<Something> things) {
        List<Something> filtered = new ArrayList<>();
        for (Something s : things) {
            if (s.getAmount() > 100.00) {
                if (s.getAmount() < 1000.00) {
                    filtered.add(s);
                }
            }
        }
        return filtered;
    }

    public static double sum(List<Something> things) {
        double d = 0.0;
        for (Something s : things) {
            d += s.getAmount();
        }
        return d;
    }

}

And now Java 8 style – streaming:

import java.util.stream.Collectors;

public class CollectionB {

    public static void main(String... args) {

        List<Something> things = Helper.someThings();

        System.err.println("Filter lambda");
        List<Something> filtered = things.stream().parallel().filter( t -> t.getAmount() > 100.00 && t.getAmount() < 1000.00).collect(Collectors.toList());
        System.err.println(filtered);

        System.err.println("Sum lambda");
        double sum = filtered.stream().mapToDouble(t -> t.getAmount()).sum();
        System.err.println(sum);

    }

}

The import java.util.function.* interfaces & method references

public class CollectionC {

    public static void main(String... args) {

        List<Something> things = Helper.someThings();

        System.err.println("Do something");
        doSomething(things, new Doer<Something>() {

            @Override
            public void doSomething(Something t) {
                System.err.println(t);
            }
        });
    }

    public static void doSomething(List<Something> things, Doer<Something> doer) {
        for (Something s : things) {
            doer.doSomething(s);
        }
    }

}

Replace our Doer interface with the standard Consumer interface (previously known as Block)

import java.util.function.Consumer;

public class CollectionD {

    public static void main(String... args) {

        List<Something> things = Helper.someThings();

        System.err.println("Do something functional interfaces");
        consumeSomething(things, new Consumer<Something>() {

            @Override
            public void accept(Something t) {
                System.err.println(t);
            }
        });

        System.err.println("Do something functional interfaces, using lambda");
        consumeSomething(things, (t) -> System.err.println(t));

        System.err.println("Do something functional interfaces, using lambda method reference (new operator ::) ");
        consumeSomething(things, System.err::println);

        System.err.println("Do something functional interfaces, using stream");
        things.stream().forEach(new Consumer<Something>() {

            @Override
            public void accept(Something t) {
                System.err.println(t);
            }
        });

        System.err.println("Do something functional interfaces, using stream and method reference");
        things.stream().forEach(System.err::println);
    }

    public static void doSomething(List<Something> things, Doer<Something> doer) {
        for (Something s : things) {
            doer.doSomething(s);
        }
    }

    public static void consumeSomething(List<Something> things, Consumer<Something> consumer) {
        for (Something s : things) {
            consumer.accept(s);
        }
    }

}

Map, reduce, lazy & optional

import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.stream.Collectors;

public class Various {

    public static void main(String... args) {

        List<Something> things = Helper.someThings();

        //Map
        System.err.println(things.stream().map((Something t) -> t.getAmount()).collect(Collectors.toList()));

        //Reduce
        double d = things.stream().reduce(new Something(0.0), (Something t, Something u) -> new Something(t.getAmount() + u.getAmount())).getAmount();
        System.err.println(d);

        //Reduce again
        System.err.println(things.stream().reduce((Something t, Something u) -> new Something(t.getAmount() + u.getAmount())).get());

        //Map/reduce
        System.err.println(things.stream().map((Something t) -> t.getAmount()).reduce(0.0, (x, y) -> x + y));

        //Lazy
        Optional<Something> findFirst = things.stream().filter(t -> t.getAmount() > 1000).findFirst();
        System.err.println(findFirst.get());

        //Lazy no value
        Optional<Something> findFirstNotThere = things.stream().filter(t -> t.getAmount() > 2000).findFirst();
        try {
            System.err.println(findFirstNotThere.get());
        } catch (NoSuchElementException e) {
            System.err.println("Optional was not null, but its value was");
        }
        //Optional one step deeper
        things.stream().filter(t -> t.getAmount() > 1000).findFirst().ifPresent(t -> System.err.println("Here I am"));

    }

}

 

Reference: Java 8 lambda walkthrough from our JCG partner Kim Saabye Pedersen at the Kim Saabye Pedersen’s blog blog.
Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You'll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You'll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

Leave a Reply


two + 2 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books