Java 8 Lambda Expressions

232f987cbe47dd7083918ff2b641cf4b?s=47 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.

232f987cbe47dd7083918ff2b641cf4b?s=128

Takipi

April 30, 2014
Tweet

Transcript

  1. 2.

    Outline • What are lambda expressions? • Java 8 lambdas

    + Stream API • Syntax • Under the hood • Questions
  2. 5.

    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. 6.

    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. 7.

    Lambda expressions Java < 8 Collections.sort(list, new Comparator<String>() { @Override

    public int compare(String x, String y) { return x.compareTo(y); } });
  5. 8.

    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. 9.

    Lambda expressions List<Integer> list = Arrays.asList(3, 9, 12, -1); int

    factor = getFactor(); list.forEach(x -> System.out.println(x * factor));
  7. 13.

    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. 14.

    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. 15.

    When can we use λs? Java 8 new Thread(() ->

    { System.out.println("Lambdas can have"); System.out.println("multiple statements"); }).start();
  10. 17.

    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. 18.

    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. 19.

    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. 20.

    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. 21.

    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. 22.

    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. 23.

    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. 24.
  18. 25.
  19. 26.

    Syntax • (int x) -> { int y = x

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

    Syntax • (int x) -> { int y = x

    + 1; return y; } • (int x) -> { return x + 1; } • (int x) -> x + 1
  21. 28.

    Syntax • (int x) -> { int y = x

    + 1; return y; } • (int x) -> { return x + 1; } • (int x) -> x + 1 • (x) -> x + 1
  22. 29.

    Syntax • (int x) -> { int y = x

    + 1; return y; } • (int x) -> { return x + 1; } • (int x) -> x + 1 • (x) -> x + 1 • x -> x + 1
  23. 30.

    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
  24. 31.

    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));
  25. 34.

    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
  26. 37.

    Java bytecode • Designed for Java 1 • Strict Object-Oriented

    specification • Highly-performant on modern JVMs
  27. 42.

    Desugaring class A { public void foo() { List<String> list

    = ... list.forEach(s -> System.out.println(s)); } }
  28. 43.

    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); } }
  29. 44.

    Desugaring class B { public void foo() { List<Integer> list

    = ... int factor = ... list.map(n -> n * factor); } }
  30. 45.

    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; } }
  31. 51.
  32. 52.

    The Lambda Metafactory • “invokedynamic” encountered • Metafactory is invoked

    once • ...returns a specific “Lambda Factory” • Call site linked to the specific factory forever
  33. 54.

    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); } }
  34. 56.

    The Lambda Factory class A { public void foo() {

    List<String> list = ... list.forEach([lambda$1Factory]); } }
  35. 60.
  36. 62.

    But why? • Try not to touch the bytecode specification

    • Delegates lambda handling to the JVM
  37. 63.

    But why? • Try not to touch the bytecode specification

    • Delegates lambda handling to the JVM • While allowing the compiler minimal control
  38. 64.

    But why? • Try not to touch the bytecode specification

    • Delegates lambda handling to the JVM • While allowing the compiler minimal control
  39. 65.

    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
  40. 66.

    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