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:
1 2 3 | 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:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | 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(); } } |
01 02 03 04 05 06 07 08 09 10 | public class ThreadB { public static void main(String[] args) { new Thread(() -> { System.err.println( "Hello from lambda" ); }).start(); } } |
Note the syntax, informally as
1 | ()|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
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | 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
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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)
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | 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
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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.