6.
! Don't break binary compatibility
! Avoid introducing source incompatibilities.
! Manage behavioral compatibility change
Extends to Language Evolution
7.
! Continue to recognize old class files
! Limit cases where current legal code stops compiling
! Avoid changes in code generation introducing behavioral changes
9.
! Language
– Lambda Expressions (Closures)
– Interface Evolution (default methods)
! Libraries
– Bulk data operations on Collections
– More library support for Parallelism
! JVM
– Default Methods
– Enhancement to invokedynamic
11.
! A Lambda expression is an anonymous method.
– Has an argument list, a return type and a body.
! (Object o) - o.toString()
– Can refer to values from the enclosing lexical scope.
! (Person p) - p.getName().equals(name)
! A method reference is a reference to an existing method.
– Object :: toString
! Allow you to treat code as data.
– Behavior can be stored in variables and passed to methods.
14.
! Lets say I write a code to check marathon method.
! Check each marathon. If it can’t be finished on time, return the marathon that
can be a problem, otherwise return null.
private Marathon checkMarathons(ListMarathon problemMarathons) {
Marathon problemMarathon = null;
IteratorMarathon marathonItr = problemMarathons.iterator();
while (marathonItr.hasNext() problemMarathon == null) {
Marathon marathon = marathonItr.next();
problemMarathon = chckMarathon(marathon);
}
return problemMarathon;
}
– Loop is inherently sequential.
– Client has to manage iteration and parallelization if needed.
– bring the data to the code
17.
! We could write this as
private OptionalMarathon checkMarathons(ListMarathon problemMarathons) {
return problemMarathons.stream().
map(p-checkMarathon(p)).
filter(p- p!=null).
findfirst();
}
–
–
–
–
bring the operation to the data
Library free to use parallelism(like fork/join), out-of-order execution, laziness.
Client passes behavior into APIs as data
Enables APIs designers to build more powerful, expressive APIs.
! And easily make it execute in parallel !!!
20.
! Interfaces are a double-edged sword
– Cannot compatibly evolve them unless you control all implementations
– Reality : APIs age
– What to do with old APIs :
! Let the APIs stagnate
! Replace it in entirely
! Modify existing APIs
! Burden of API evolution should fall to implementors, not users.
22.
! We have used single-method interfaces to represent functions
– Runnable, Comparator, ActionListener
! Lets call them Functional Interfaces.
! And introduce some new ones like PredicateT, BlockT
! A lambda expression evaluates to an instance of a functional inte
rface.
– PredicateString isEmpty = s-s.isEmpty();
– PredicateString isEmpty = String::isEmpty;
– Runnable r = ()-{System.out.println(“lambda”);}
24.
! Instead of supplying values to specific library methods like here
public interface CollectionE {
boolean remove(Object o);
}
! We’re going to supply behavior to general library methods.
public interface CollectionE {
boolean removeIf(Predicate? Super E p);
}
! Each stage has specific operation
! Client code reads like problem statement
Predicate is an interface with a single abstract boolean-valued method test. removeIf() executes test fo
r each element and if test() returns true, removeIf() removes that element.
26.
! A default method provides an implementation in the interface.
! Woven in by the VM at link time.
! Multiple Inheritance?
– Java always had multiple inheritance of TYPES
– This adds multiple inheritance of BEHAVIOR
interface CollectionT {
...
default void forEach(BlockT action) {
for (T t : this)
action.apply(t);
}
}
28.
! Rule 1 – prefer superclass methods to interface methods (Class
wins)
! Rule 2 – prefer more specific interfaces to less (Subtype wins)
! Rule 3 – otherwise, act as if the method is abstract. In the case of
conflicting defaults, the concrete class must provide an impleme
ntation.
34.
Bulk operations on collections also enable a map / reduce style of progra
mming. For example, the above code could be further decomposed by gett
ing a stream from the shapes collection, filtering the red elements, and the
n iterating only over the filtered elements.
shapes.stream()
.filter(s - s.getColor() == RED)
.forEach(s - { s.setColor(BLUE); });
! Compose compound operations from basic building blocks.
! Each stage has specific operation
! Client code reads like problem statement
36.
Streams
! Represents streams of values, not a data structure.
! Source can be collection, array, functions, I/O…
collection.stream()
.filter(f-f.isBlue())
.map(f-f.getBar())
.forEach(System.out…);
Fork/Join Parallelism
! Powerful and efficient but not so easy
! Divide problem into subsets, solve in parallel and combine results.
38.
! Collection.parallel().filter(…).map(…).reduce(…);
! ConcurrentHashMap.parallel(ForkJoinPool)
– Returns parallel view of CHM
– Methods : forEach, forEachEntry, forEachKey, forEachValue
– Consider forEachValue(ConcurrentHashMap.ActionV action)
! Creates a new ForEachValueTask
! Subclass of ForkJoinTask
! Submits that to the ForkJoinPool
! ForkJoinPool executes ForEachValueTask on one of its threads.
41.
! ConcurrentHashMap.ForEachValueTask
@SupressWarnings(“unchecked”) public final void compute() {
final ActionV action = this.action;
if (action == null) throw new Error(NullFunctionMessage);
int b = batch(), c;
while (b 1 baseIndex != baseLimit) {
do{} while (@casPending(c=pending, c+1));
new ForEachValueTaskK,V(this, b=1, true, action).fork();
Object v;
while ((v == advance()) != null)
action.apply((V)v);
tryComplete();
}
}
43.
! Sorting a list using comparator
Collections.sort(planList, new ComparatorPlan() {
public int compare(Plan P1, Plan P2) {
return P1.getTask().compareTo(P2.getTask());
}
}
The method compare must extract the first level sort keys and then compare them.
! Suppose we have a method that accepts and returns behaviors :
ComparatorT comparing(MapperT,U m);
Now, its much easier to create custom comparators :
ComparatorPlan byTask = Comparators.compare(p-getTask));
ComparatorPlan byDuration = Comparators.compare(p-getDuration));
45.
! Methods and Comparators can now be composed
– new Comparator method
Collections.sort(planList, byTask.compose(byDuration));
And also
planList.sort(byTask.compose(byDuration));
47.
! Using an anonymous inner class??
problemMarathon.removeIf(new PredicateMarathon() {
public boolean test(Marathon p) {
return p.equals(problemMarathon)
}
});
! Let the static compiler emit a declarative recipe for creating a lambda.
! Let the runtime execute that recipe however it deems best
! This is like a job for invokedynamic??
52.
! The JVM has 4 bytecodes for method invocation :
–
–
–
–
invokestatic for static methods.
invokevirtual for class methods
invokeinterface interface methods
invokespecial for constructors, private methods and super calls.
! New Bytecode Tool – invokedynamic
– The JVM adds a fifth invocation mode: invokedynamic (indy)
– Behavior of invoke(virtual, static, interface) are fixed.
54.
! Any indy call site has three group of operands :
– A bootstrap method
– A static argument list
– A dynamic argument list
! We use indy to embed a recipe for constructing a lambda at the capture
site.
– Desugared implementation method.
– Functional interface we are converting to.
– Values captured from lexical scope.
! The captured site is called lambda factory.
– Invoked with indy, returns an instance of functional interface
63.
! We generate an indy call site, which returns the lambda.
– This is the lambda factory.
– Bootstrap for the lambda factory selects the translation strategy. Bootstrap
is called the lambda metafactory.
list.removeAll(p-p.getAge() = minAge);
Predicate $p = indy[bootstrap=LambdaMetafactory, staticargs=[Predicate,
lambda$1], dynargs=[minAge]];
list.removeAll($p);
Private static boolean lambda$1(int capturedK, Person p) {
return p.getAge() = capturedK;
}
– Captured arguments passed to lambda factory.