© 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
© Copyright Azul Systems 2017
Agenda
 Java Lambda expressions
 Lambda expression performance
 How far can we take lambdas?
 Summary
2
© Copyright Azul Systems 2017
Java Lambda Expressions
© 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
© 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
© 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++));
}
}
© 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
© 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;
© 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
© 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
© 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
© Copyright Azul Systems 2017
Lambda Expression
Performance
© 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);
© 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
© 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
© 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
© 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
© Copyright Azul Systems 2017
How Far Can We Take
Lambdas?
With inspiration from Jarek Ratajski
© Copyright Azul Systems 2017 19
Alonso Church
The λ Calculus (1936)
What does this have to do with Java?
© 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
© Copyright Azul Systems 2017
Functional Interface
@FunctionalInterface
public interface Lambda {
Lambda apply(Lambda lambda);
}
© Copyright Azul Systems 2017
Function Basics
 Identity [ λx.x ]
Lambda identity = x -> x;
Lambda identity = new Lambda {
Lambda apply(Lambda x) {
return x;
}
};
© 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;
}
}}};
© 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;
}
}}};
© 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
© 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
© 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) ]
© 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
© 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)
© 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))
© 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))
© 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))
© 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))
© 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!
© Copyright Azul Systems 2017
Summary
© 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
© 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
© 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

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

  • 1.
    © Copyright AzulSystems 2017 © Copyright Azul Systems 2015 @speakjava It’s Java, Jim, But Not As We Know It! Simon Ritter Deputy CTO, Azul Systems 1
  • 2.
    © Copyright AzulSystems 2017 Agenda  Java Lambda expressions  Lambda expression performance  How far can we take lambdas?  Summary 2
  • 3.
    © Copyright AzulSystems 2017 Java Lambda Expressions
  • 4.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 2017 Capturing Lambdas 6 class DataProcessor { private int currentValue; public void process() { DataSet myData = myFactory.getDataSet(); dataSet.forEach(d -> d.use(currentValue++)); } }
  • 7.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 2017 Lambda Expression Performance
  • 13.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 2017 How Far Can We Take Lambdas? With inspiration from Jarek Ratajski
  • 19.
    © Copyright AzulSystems 2017 19 Alonso Church The λ Calculus (1936) What does this have to do with Java?
  • 20.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 2017 Functional Interface @FunctionalInterface public interface Lambda { Lambda apply(Lambda lambda); }
  • 22.
    © Copyright AzulSystems 2017 Function Basics  Identity [ λx.x ] Lambda identity = x -> x; Lambda identity = new Lambda { Lambda apply(Lambda x) { return x; } };
  • 23.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 2017 Summary
  • 36.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 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.
    © Copyright AzulSystems 2017 © Copyright Azul Systems 2015 @speakjava It’s Java, Jim, But Not As We Know It! Simon Ritter Deputy CTO, Azul Systems 38

Editor's Notes

  • #14  ISOMORPHIC Libraries are backwardly compatible