Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Java 8 Lambda Expressions

Takipi
April 30, 2014

Java 8 Lambda Expressions

Java 8 introduced a change named Java's biggest ever -- lambda expressions. In this talk we'll explore lambda expressions, when and how to use them, then dive even deeper and see how they work under the hood.

Takipi

April 30, 2014
Tweet

More Decks by Takipi

Other Decks in Programming

Transcript

  1. Outline • What are lambda expressions? • Java 8 lambdas

    + Stream API • Syntax • Under the hood • Questions
  2. Lambda expressions List<String> list = Arrays.asList( "Say", "hello", "to", "Java

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

    8", "Lambdas"); Collections.sort(list, new Comparator<String>() { @Override public int compare(String s1, String s2) { return s1.compareTo(s2); } }); System.out.println(list);
  4. Lambda expressions Java < 8 Collections.sort(list, new Comparator<String>() { @Override

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

    public int compare(String x, String y) { return x.compareTo(y); } }); Java 8 list.sort((x, y) -> x.compareTo(y));
  6. Lambda expressions List<Integer> list = Arrays.asList(3, 9, 12, -1); int

    factor = getFactor(); list.forEach(x -> System.out.println(x * factor));
  7. When can we use λs? @FunctionalInterface public interface Comparator<T> {

    int compare(T o1, T o2); } @FunctionalInterface public interface Predicate<T> { boolean test(T t); }
  8. 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();
  9. When can we use λs? Java 8 new Thread(() ->

    { System.out.println("Lambdas can have"); System.out.println("multiple statements"); }).start();
  10. Streams + Lambdas List<Double> prices = Arrays.asList(1000.0, 150.0, 499.0); List<Double>

    newPrices = new ArrayList<Double>(); 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); }
  11. Streams + Lambdas List<Double> 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));
  12. Streams + Lambdas List<Double> 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
  13. Streams + Lambdas List<Double> 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
  14. Streams + Lambdas List<Double> 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
  15. Streams + Lambdas List<Double> 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
  16. Streams + Lambdas List<Double> 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
  17. Syntax • (int x) -> { int y = x

    + 1; return y; } • (int x) -> { return x + 1; }
  18. Syntax • (int x) -> { int y = x

    + 1; return y; } • (int x) -> { return x + 1; } • (int x) -> x + 1
  19. Syntax • (int x) -> { int y = x

    + 1; return y; } • (int x) -> { return x + 1; } • (int x) -> x + 1 • (x) -> x + 1
  20. Syntax • (int x) -> { int y = x

    + 1; return y; } • (int x) -> { return x + 1; } • (int x) -> x + 1 • (x) -> x + 1 • x -> x + 1
  21. 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
  22. Off-topic: Method references List<Double> 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));
  23. 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
  24. Java bytecode • Designed for Java 1 • Strict Object-Oriented

    specification • Highly-performant on modern JVMs
  25. Desugaring class A { public void foo() { List<String> list

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

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

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

    = ... int factor = ... list.map([await link of lambda$1 as Function]); } private static Integer lambda$1(int factor, Integer n) { return n * factor; } }
  29. The Lambda Metafactory • “invokedynamic” encountered • Metafactory is invoked

    once • ...returns a specific “Lambda Factory” • Call site linked to the specific factory forever
  30. The Lambda Factory class A { public void foo() {

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

    List<String> list = ... list.forEach([lambda$1Factory]); } }
  32. But why? • Try not to touch the bytecode specification

    • Delegates lambda handling to the JVM
  33. But why? • Try not to touch the bytecode specification

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

    • Delegates lambda handling to the JVM • While allowing the compiler minimal control
  35. 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
  36. 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