Core Java

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.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button