Contenu connexe Similaire à It's Java Jim, But Not As We Know It! Similaire à It's Java Jim, But Not As We Know It! (20) Plus de Simon Ritter (20) It's Java Jim, But Not As We Know It!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. © Copyright Azul Systems 2017
Agenda
Java Lambda expressions
Lambda expression performance
How far can we take lambdas?
Summary
2
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. © 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. © 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. © 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. © 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. © 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. © 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. © 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
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. © 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. © 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. © 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. © 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. © Copyright Azul Systems 2017
How Far Can We Take
Lambdas?
With inspiration from Jarek Ratajski
19. © Copyright Azul Systems 2017 19
Alonso Church
The λ Calculus (1936)
What does this have to do with Java?
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. © Copyright Azul Systems 2017
Functional Interface
@FunctionalInterface
public interface Lambda {
Lambda apply(Lambda lambda);
}
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. © 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. © 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. © 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. © 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. © 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. © 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. © 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. © 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. © 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. © 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. © 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. © 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!
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. © 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. © 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
Notes de l'éditeur
ISOMORPHIC
Libraries are backwardly compatible