Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

It's Java Jim, But Not As We Know It!

1,736 views

Published on

A dive into the world of Lambda expressions in JDK 8, covering the fundamental ideas, some gotchas and a discussion of performance. Finally, just how far can you take Lambdas in Java?

Published in: Software
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

It's Java Jim, But Not As We Know It!

  1. 1. © Copyright Azul Systems 2017 © Copyright Azul Systems 2015 @speakjava It’s Java, Jim, But Not As We Know It! Simon Ritter Deputy CTO, Azul Systems 1
  2. 2. © Copyright Azul Systems 2017 Agenda  Java Lambda expressions  Lambda expression performance  How far can we take lambdas?  Summary 2
  3. 3. © Copyright Azul Systems 2017 Java Lambda Expressions
  4. 4. © Copyright Azul Systems 2017 JDK 8 Lambda Expressions  Simplified representation of behaviour in Java – Anonymous inner class is clunky  Assign to variable, pass as parameter  Use wherever the type is a Functional Interface – Much simpler than adding a function type to Java – Single abstract method – Not necessarily single method  default and static methods don’t count 4
  5. 5. © Copyright Azul Systems 2017 Lambda Expression Syntax  Like a method – But not associated with a class – Typed parameters, body, return type, exceptions  Closure over values, not types – Only capture effectively-final variables 5 (parameters) -> body Lambda operator
  6. 6. © Copyright Azul Systems 2017 Capturing Lambdas 6 class DataProcessor { private int currentValue; public void process() { DataSet myData = myFactory.getDataSet(); dataSet.forEach(d -> d.use(currentValue++)); } }
  7. 7. © Copyright Azul Systems 2017 Capturing Lambdas 7 class DataProcessor { private int currentValue; public void process() { DataSet myData = myFactory.getDataSet(); dataSet.forEach(d -> d.use(this.currentValue++)); } } Reference to this inserted by compiler
  8. 8. © Copyright Azul Systems 2017 Method References  Method references let us reuse a method as a lambda expression FileFilter x = File f -> f.canRead(); FileFilter x = File::canRead;
  9. 9. © Copyright Azul Systems 2017 Method References  Format: target_reference::method_name  Three kinds of method reference – Static method – Instance method of an arbitrary type – Instance method of an existing object 9
  10. 10. © Copyright Azul Systems 2017 Method References 10 Lambda Method Ref Lambda Method Ref Lambda Method Ref (args) -> ClassName.staticMethod(args) (arg0, rest) -> arg0.instanceMethod(rest) (args) -> expr.instanceMethod(args) ClassName::staticMethod ClassName::instanceMethod expr::instanceMethod Rules For Construction
  11. 11. © Copyright Azul Systems 2017 Method References (String s) -> Integer.parseInt(s); (String s, int i) -> s.substring(i) Axis a -> getLength(a) Integer::parseInt String::substring this::getLength Lambda Method Ref Lambda Method Ref Lambda Method Ref Examples
  12. 12. © Copyright Azul Systems 2017 Lambda Expression Performance
  13. 13. © Copyright Azul Systems 2017 Lambdas & Anonymous Inner Classes  Functionally equivalent 13 myList.forEach(w -> System.out.println(w)); myList.forEach(new Consumer<String>() { @Override public void accept(String w) { System.out.println(w); } }); myList.forEach(System.out::println);
  14. 14. © Copyright Azul Systems 2017 Anonymous Inner Classes  As the name suggests, we are dealing with classes – Compiler generates class with name like Foo$1 – Type pollution  The class must be loaded at run time  Instantiated like any other class  Lambda expressions could be implemented this way – Originally they were – Forces an inner class where you didn’t ask for it  You wanted a function 14
  15. 15. © Copyright Azul Systems 2017 Lambda Implementation  A better answer: invokedynamic – Introduced in Java SE 7 to improve performance of dynamically typed languages running on the JVM – Defers implementation of the Lambda to runtime  Lambda compilation – Generate invokedynamic call (lambda factory)  java.lang.LambdaMetaFactory  Return instance of (lambda) functional interface type – Convert body of lambda to method  Not necessary for method references 15
  16. 16. © Copyright Azul Systems 2017 Lambda Implementation  Non-capturing Lambda – Simple conversion to static method in the class where the lambda is used  Capturing Lambdas – Static method with captured variables prepended as parameters – Synthetic instance method of class using Lambda  Lambda invokes a class method 16
  17. 17. © Copyright Azul Systems 2017 Implementation Differences  Lambdas – Linkage (CallSite) – Capture – Invocation 17  Anonymous inner classes – Class loading – Instantiation – Invocation  Non-capturing lambdas automatically optimise  Method references are slightly more optimal  -XX:+TieredCompilation gives better Lambda results – Advice is don’t use -XX:-TieredCompilation
  18. 18. © Copyright Azul Systems 2017 How Far Can We Take Lambdas? With inspiration from Jarek Ratajski
  19. 19. © Copyright Azul Systems 2017 19 Alonso Church The λ Calculus (1936) What does this have to do with Java?
  20. 20. © Copyright Azul Systems 2017 Exploding Head Lambdas  Java programmers are typically imperative programmers  Functional programming is not imperative – As we’ll see  Lambda Calculus and Turing Machines are equivalent  But will give you a headache – At least it did me!  What can we do only using Lambda expressions? – And one functional interface 20
  21. 21. © Copyright Azul Systems 2017 Functional Interface @FunctionalInterface public interface Lambda { Lambda apply(Lambda lambda); }
  22. 22. © Copyright Azul Systems 2017 Function Basics  Identity [ λx.x ] Lambda identity = x -> x; Lambda identity = new Lambda { Lambda apply(Lambda x) { return x; } };
  23. 23. © Copyright Azul Systems 2017 Function Basics (Booleans)  Boolean false [ λf.λx.x ] boolFalse = f -> (x -> x); // Always returns identity boolFalse = new Lambda { Lambda apply(Lambda f) { return new Lambda { Lambda apply(Lambda x) { return x; } }}};
  24. 24. © Copyright Azul Systems 2017 Function Basics (Booleans)  Boolean true [ λf.λx.f ] boolTrue = f -> (x -> f); // Never returns identity boolTrue = new Lambda { Lambda apply(Lambda f) { return new Lambda { Lambda apply(Lambda x) { return f; } }}};
  25. 25. © Copyright Azul Systems 2017 Church Numerals  Zero [ λf.λx.x ] • Identity for addition and subtraction (a ± 0 = a) • The Lambda is the same as false • The function is applied zero times to the argument zero = f -> x -> x;  One [ λf.λx.(f x) ] one = f -> x -> f.apply(x);  Two [ λf.λx.(f (f x)) ] two = f -> x -> f.apply(f.apply(x)); 25
  26. 26. © Copyright Azul Systems 2017 Church Encoding  Successor: n++ [ λn.λf.λx.f(n f x) ] successor = n -> f -> x -> f.apply(n.apply(f).apply(x)); 26
  27. 27. © Copyright Azul Systems 2017 Church Encoding  Predecessor: n-- 27 predecessor = n -> f -> x -> n.apply(g -> h -> h.apply(g.apply(f))) .apply(u -> x).apply(u -> u); [ λn.λf.λx.n(λg.λh.h(g f))(λu.x)(λu.u) ]
  28. 28. © Copyright Azul Systems 2017 Church Encoding  Add: m + n [ λm.λn.λf.λx ((m f) ((n f) x)) ] m -> n -> f -> x -> m.apply(f).apply(n.apply(f).apply(x))  Subtract: m - n [ λm.λn.(n predecessor) m ] m -> n -> m.apply(predecessor).apply(n) 28
  29. 29. © Copyright Azul Systems 2017 Solving 2 + 2 With Lambdas Lambda two = f -> x -> f.apply(f.apply(x)); Lambda plus = m -> n -> f -> x -> m.apply(f).apply(n.apply(f).apply(x)); Lambda four = plus.apply(two).apply(two); 4 = + 2 2 (Polish notation)
  30. 30. © Copyright Azul Systems 2017 Solving 2 + 2 With Lambdas m -> n -> f -> x -> m.apply(f).apply(n.apply(f).apply(x)) n -> f -> x -> f -> x -> f.apply(f.apply(x)).apply(f) .apply(n.apply(f).apply(x))
  31. 31. © Copyright Azul Systems 2017 Solving 2 + 2 With Lambdas m -> n -> f -> x -> m.apply(f).apply(n.apply(f).apply(x)) n -> f -> x -> f -> x -> f.apply(f.apply(x)).apply(f) .apply(n.apply(f).apply(x)) f -> x -> f -> x -> f.apply(f.apply(x)).apply(f) .apply(f -> x -> f.apply(f.apply(x).apply(f).apply(x))
  32. 32. © Copyright Azul Systems 2017 Solving 2 + 2 With Lambdas f -> x -> f -> x -> f.apply(f.apply(x)).apply(f) .apply(f -> x -> f.apply(f.apply(x)).apply(f).apply(x)) f -> x -> x -> f.apply(f.apply(x)) .apply(f -> x -> f.apply(f.apply(x)).apply(f).apply(x))
  33. 33. © Copyright Azul Systems 2017 Solving 2 + 2 With Lambdas f -> x -> f -> x -> f.apply(f.apply(x)).apply(f) .apply(f -> x -> f.apply(f.apply(x)).apply(f).apply(x)) f -> x -> x -> f.apply(f.apply(x)) .apply(f -> x -> f.apply(f.apply(x)).apply(f).apply(x)) f -> x -> x -> f.apply(f.apply(x)) .apply(x -> f.apply(f.apply(x)).apply(x))
  34. 34. © Copyright Azul Systems 2017 Solving 2 + 2 With Lambdas f -> x -> x -> f.apply(f.apply(x)) .apply(x -> f.apply(f.apply(x)).apply(x)) f -> x -> x -> f.apply(f.apply(x)) .apply(f.apply(f.apply(x))) f -> x -> x -> f.apply(f.apply(x)) .apply(f.apply(f.apply(x))) f -> x -> f.apply(f.apply(f.apply(f.apply(x))) = 4!
  35. 35. © Copyright Azul Systems 2017 Summary
  36. 36. © Copyright Azul Systems 2017 Lambda Expressions  Very useful and powerful – Succinct way to parameterise behaviour  Better performance than anonymous inner class – Invokedynamic implementation  Can be used in weird and wonderful ways – Not necessarily to be recommended! 36
  37. 37. © Copyright Azul Systems 2017 More Information  Dixin Yan’s blog – weblogs.asp.net/dixin (C# based, but useful) – October 2016  Jarek’s presentation from Voxxed Zurich – https://www.youtube.com/watch?v=Dun8ewSeX6c 37
  38. 38. © Copyright Azul Systems 2017 © Copyright Azul Systems 2015 @speakjava It’s Java, Jim, But Not As We Know It! Simon Ritter Deputy CTO, Azul Systems 38

×