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.

