Slide 1

Slide 1 text

Java 8 λs IL JUG, April 2014 Niv Steingarten, Takipi

Slide 2

Slide 2 text

Outline ● What are lambda expressions? ● Java 8 lambdas + Stream API ● Syntax ● Under the hood ● Questions

Slide 3

Slide 3 text

Lambda expressions

Slide 4

Slide 4 text

Lambda expressions Anonymous implementation of a functional interface

Slide 5

Slide 5 text

Lambda expressions List list = Arrays.asList( "Say", "hello", "to", "Java 8", "Lambdas"); Collections.sort(list, new Comparator() { @Override public int compare(String x, String y) { return x.compareTo(y); } }); System.out.println(list);

Slide 6

Slide 6 text

Lambda expressions List list = Arrays.asList( "Say", "hello", "to", "Java 8", "Lambdas"); Collections.sort(list, new Comparator() { @Override public int compare(String s1, String s2) { return s1.compareTo(s2); } }); System.out.println(list);

Slide 7

Slide 7 text

Lambda expressions Java < 8 Collections.sort(list, new Comparator() { @Override public int compare(String x, String y) { return x.compareTo(y); } });

Slide 8

Slide 8 text

Lambda expressions Java < 8 Collections.sort(list, new Comparator() { @Override public int compare(String x, String y) { return x.compareTo(y); } }); Java 8 list.sort((x, y) -> x.compareTo(y));

Slide 9

Slide 9 text

Lambda expressions List list = Arrays.asList(3, 9, 12, -1); int factor = getFactor(); list.forEach(x -> System.out.println(x * factor));

Slide 10

Slide 10 text

When can we use λs?

Slide 11

Slide 11 text

When can we use λs? “SAM” Single Abstract Method

Slide 12

Slide 12 text

When can we use λs? @FunctionalInterface public interface Comparator { int compare(T o1, T o2); }

Slide 13

Slide 13 text

When can we use λs? @FunctionalInterface public interface Comparator { int compare(T o1, T o2); } @FunctionalInterface public interface Predicate { boolean test(T t); }

Slide 14

Slide 14 text

When can we use λs? Java < 8 new Thread(new Runnable() { @Override public void run() { System.out.println("Lambdas can have"); System.out.println("multiple statements"); } }).start();

Slide 15

Slide 15 text

When can we use λs? Java 8 new Thread(() -> { System.out.println("Lambdas can have"); System.out.println("multiple statements"); }).start();

Slide 16

Slide 16 text

Streams + Lambdas

Slide 17

Slide 17 text

Streams + Lambdas List prices = Arrays.asList(1000.0, 150.0, 499.0); List newPrices = new ArrayList(); for (Double p : prices) { System.out.println(p); if (p > 300) { newPrices.add(p * (1.0 - dailyDiscount)); } } Collections.sort(newPrices); for (Double p : newPrices) { System.out.println(p); }

Slide 18

Slide 18 text

Streams + Lambdas List prices = Arrays.asList(1000.0, 150.0, 499.0); prices.stream() .peek(p -> System.out.println(p)) .filter(p -> (p > 300)) .map(p -> p * (1.0 - dailyDiscount)) .sorted() .forEach(p -> System.out.println(p));

Slide 19

Slide 19 text

Streams + Lambdas List prices = Arrays.asList(1000.0, 150.0, 499.0); prices.stream() .peek(p -> System.out.println(p)) .filter(p -> (p > 300)) .map(p -> p * (1.0 - dailyDiscount)) .sorted() .forEach(p -> System.out.println(p)); Consumer: T → void

Slide 20

Slide 20 text

Streams + Lambdas List prices = Arrays.asList(1000.0, 150.0, 499.0); prices.stream() .peek(p -> System.out.println(p)) .filter(p -> (p > 300)) .map(p -> p * (1.0 - dailyDiscount)) .sorted() .forEach(p -> System.out.println(p)); Predicate: T → boolean

Slide 21

Slide 21 text

Streams + Lambdas List prices = Arrays.asList(1000.0, 150.0, 499.0); prices.stream() .peek(p -> System.out.println(p)) .filter(p -> (p > 300)) .map(p -> p * (1.0 - dailyDiscount)) .sorted() .forEach(p -> System.out.println(p)); Function: T → R

Slide 22

Slide 22 text

Streams + Lambdas List prices = Arrays.asList(1000.0, 150.0, 499.0); prices.stream() .peek(p -> System.out.println(p)) .filter(p -> (p > 300)) .map(p -> p * (1.0 - dailyDiscount)) .sorted() .forEach(p -> System.out.println(p)); Requires: T implements Comparable

Slide 23

Slide 23 text

Streams + Lambdas List prices = Arrays.asList(1000.0, 150.0, 499.0); prices.stream() .peek(p -> System.out.println(p)) .filter(p -> (p > 300)) .map(p -> p * (1.0 - dailyDiscount)) .sorted() .forEach(p -> System.out.println(p)); Consumer: (+ terminal operation) T → void

Slide 24

Slide 24 text

Syntax

Slide 25

Slide 25 text

Syntax ● (int x) -> { int y = x + 1; return y; }

Slide 26

Slide 26 text

Syntax ● (int x) -> { int y = x + 1; return y; } ● (int x) -> { return x + 1; }

Slide 27

Slide 27 text

Syntax ● (int x) -> { int y = x + 1; return y; } ● (int x) -> { return x + 1; } ● (int x) -> x + 1

Slide 28

Slide 28 text

Syntax ● (int x) -> { int y = x + 1; return y; } ● (int x) -> { return x + 1; } ● (int x) -> x + 1 ● (x) -> x + 1

Slide 29

Slide 29 text

Syntax ● (int x) -> { int y = x + 1; return y; } ● (int x) -> { return x + 1; } ● (int x) -> x + 1 ● (x) -> x + 1 ● x -> x + 1

Slide 30

Slide 30 text

Syntax ● (int x) -> { int y = x + 1; return y; } ● (int x) -> { return x + 1; } ● (int x) -> x + 1 ● (x) -> x + 1 ● x -> x + 1 ● (x, y) -> x * y

Slide 31

Slide 31 text

Off-topic: Method references List prices = Arrays.asList(1000.0, 150.0, 499.0); prices.stream() .peek(p -> System.out.println(p)) .filter(p -> (p > 300)) .map(Double::toString) .sorted() .forEach(p -> System.out.println(p));

Slide 32

Slide 32 text

Under the hood

Slide 33

Slide 33 text

Java bytecode

Slide 34

Slide 34 text

Java bytecode ALOAD 0 GETFIELD java/util/ArrayList.elementData : [Ljava/lang/Object; GETSTATIC java/util/ArrayList.EMPTY_ELEMENTDATA : [Ljava/lang/Object; IF_ACMPEQ L1 ICONST_0 GOTO L2 BIPUSH 10 ISTORE 2 ILOAD 1 ILOAD 2 IF_ICMPLE L4 ALOAD 0 ILOAD 1 INVOKESPECIAL java/util/ArrayList.ensureExplicitCapacity (I)V RETURN

Slide 35

Slide 35 text

Java bytecode ● Designed for Java 1

Slide 36

Slide 36 text

Java bytecode ● Designed for Java 1 ● Strict Object-Oriented specification

Slide 37

Slide 37 text

Java bytecode ● Designed for Java 1 ● Strict Object-Oriented specification ● Highly-performant on modern JVMs

Slide 38

Slide 38 text

Under the hood List list = Arrays.asList("Alice", "Bob", "Eve"); list.forEach(s -> System.out.println(s));

Slide 39

Slide 39 text

Under the hood List list = Arrays.asList("Alice", "Bob", "Eve"); list.forEach(s -> System.out.println(s));

Slide 40

Slide 40 text

Under the hood ... aload_0 invokedynamic #0:accept:()LConsumer; invokeinterface List.forEach:(LConsumer;)V ...

Slide 41

Slide 41 text

Under the hood Step 1: Desugaring

Slide 42

Slide 42 text

Desugaring class A { public void foo() { List list = ... list.forEach(s -> System.out.println(s)); } }

Slide 43

Slide 43 text

Desugaring class A { public void foo() { List list = ... list.forEach([await link of lambda$1 Consumer]); } private static void lambda$1(String s) { System.out.println(s); } }

Slide 44

Slide 44 text

Desugaring class B { public void foo() { List list = ... int factor = ... list.map(n -> n * factor); } }

Slide 45

Slide 45 text

Desugaring class B { public void foo() { List list = ... int factor = ... list.map([await link of lambda$1 as Function]); } private static Integer lambda$1(int factor, Integer n) { return n * factor; } }

Slide 46

Slide 46 text

Under the hood Step 2: The Lambda Metafactory

Slide 47

Slide 47 text

The Lambda Metafactory metaFactory(MethodHandles.Lookup caller, String invokedName, MethodType invokedType, MethodHandle descriptor, MethodHandle impl)

Slide 48

Slide 48 text

The Lambda Metafactory

Slide 49

Slide 49 text

The Lambda Metafactory ● “invokedynamic” encountered

Slide 50

Slide 50 text

The Lambda Metafactory ● “invokedynamic” encountered ● Metafactory is invoked once

Slide 51

Slide 51 text

The Lambda Metafactory ● “invokedynamic” encountered ● Metafactory is invoked once ● ...returns a specific “Lambda Factory”

Slide 52

Slide 52 text

The Lambda Metafactory ● “invokedynamic” encountered ● Metafactory is invoked once ● ...returns a specific “Lambda Factory” ● Call site linked to the specific factory forever

Slide 53

Slide 53 text

Under the hood Step 3: The Lambda Factory

Slide 54

Slide 54 text

The Lambda Factory class A { public void foo() { List list = ... list.forEach([lambda$1 factory]); } private static void lambda$1(String s) { System.out.println(s); } }

Slide 55

Slide 55 text

The Lambda Factory class lambda$1Factory { public Consumer create(...) { ... } }

Slide 56

Slide 56 text

The Lambda Factory class A { public void foo() { List list = ... list.forEach([lambda$1Factory]); } }

Slide 57

Slide 57 text

Under the hood Step 4: The Lambda

Slide 58

Slide 58 text

The Lambda class Lambda$1Impl implements Consumer { @Override public void accept(String s) { A.lambda$1bridge(s); } }

Slide 59

Slide 59 text

The Lambda class Lambda$1Impl implements Consumer { @Override public void accept(String s) { A.lambda$1bridge(s); } }

Slide 60

Slide 60 text

But why?

Slide 61

Slide 61 text

But why? ● Try not to touch the bytecode specification

Slide 62

Slide 62 text

But why? ● Try not to touch the bytecode specification ● Delegates lambda handling to the JVM

Slide 63

Slide 63 text

But why? ● Try not to touch the bytecode specification ● Delegates lambda handling to the JVM ● While allowing the compiler minimal control

Slide 64

Slide 64 text

But why? ● Try not to touch the bytecode specification ● Delegates lambda handling to the JVM ● While allowing the compiler minimal control

Slide 65

Slide 65 text

But why? ● Try not to touch the bytecode specification ● Delegates lambda handling to the JVM ● While allowing the compiler minimal control ● Enabled runtime optimization and analysis

Slide 66

Slide 66 text

But why? ● Try not to touch the bytecode specification ● Delegates lambda handling to the JVM ● While allowing the compiler minimal control ● Enabled runtime optimization and analysis ● Allow flexibility in internal implementation

Slide 67

Slide 67 text

Thank you! Now go and be awesome. [email protected] @nivstein / @takipid