If you can't read please download the document
Upload
hendersk
View
8.422
Download
0
Embed Size (px)
Citation preview
Method Handles in Javaand some neat Java 8 stuff too!
So what are we going to talk about?
What are method handles?
How are method handles related to reflection?
What is invokedynamic about?
How are method handles used with invokedynamic?
What are lambda expressions?
How are method handles used with lambda expressions?
What are a few other interesting things coming in Java 8?
What is a method handle?
A reference to a method (or field, constructor or other bit of functionality) that can be executed
Defined in package java.util.invoke
Introduced with invokedynamic support (JSR 292) in Java 7
How is a method handle obtained?
Every method has a type that is described by a MethodType instance
MethodHandle instances are obtained using a MethodHandles.Lookup factory that knows about methods that are available in the current context
The MethodType Class
Used to describe the parameters and return type of a method handle
All instances are immutable
Instances are created using the MethodType.methodType factory method
ExamplesMethodType.methodType(BigDecimal.class, int.class) (I)Ljava/math/BigDecimal;
MethodType.methodType(String.class) - ()Ljava/lang/String;
MethodType.methodType(boolean.class, String.class) - (Ljava/lang/String;)Z;
The MethodHandles.Lookup Class
Factory for creating method handles
Created using MethodHandles.lookup method
Knows about all methods that are accessible from the calling context
Method handles are obtained from the factory using the find methods which include:findVirtual instance methods
findConstructor - constructors
findStatic class methods
How is a method handle obtained? (continued...)
Obtain a lookup context
Create a MethodType that describes the return type and parameters of the method
Get a MethodHandle instance representing the method using the appropriate find method
ExampleMethodHandles.Lookup lookup = MethodHandles.lookup();MethodType mt = MethodType.methodType(BigDecimal.class, int.class)MethodHandle power = lookup.findVirtual(BigDecimal.class, "pow", mt);
How is a method handle invoked?
Invoked using one of the MethodHandle invoke methodsinvokeExact types of arguments must exactly match the parameter types
invoke transformations will be performed on arguments prior to invocation attempt (e.g. boxing, unboxing, widening)
Method Handle Invocation Examples
// Obtain a lookup context MethodHandles.Lookup lookup = MethodHandles.lookup();// Construct the method typeMethodType mt = MethodType.methodType(BigDecimal.class, int.class);// Obtain the method handleMethodHandle power = lookup.findVirtual(BigDecimal.class, "pow", mt);// Invoke the methodBigDecimal p = (BigDecimal)power.invoke(new BigDecimal(5), 2);p = (BigDecimal)power.invoke(new BigDecimal(5), (byte)2);p = (BigDecimal)power.invoke(new BigDecimal(5), new Integer(2));p = (BigDecimal)power.invokeExact(new BigDecimal(5), 2);// These don't work because arguments or return type don't match//p = (BigDecimal)power.invokeExact(new BigDecimal(5), (byte)2);//p = (BigDecimal)power.invokeExact(new BigDecimal(5), new Integer(2));//Object o = power.invokeExact(new BigDecimal(5), 2);
How are method handles related to reflection?
Convert from Method instance to MethodHandle instance using MethodHandles.Lookup.unreflect method
Method handles more efficient because access at lookup time rather than at invocation time
Method handle API requires pretty specific knowledge of signature to obtain a method handle, unlike reflection
At the end of the day, method handles are the future of introspection
Method Handle API Functional-Flavored Features
MethodHandles class provides methods that can construct method handles from other method handles
ExamplesdropArguments remove arguments
filterArguments pre-process arguments, filter for each
filterReturnValue post-process return value
foldArguments pre-process arguments, apply combiner
guardWithTest applies test to determine invocation
insertArguments binds argument values
permuteArguments reorders arguments
Example insertArgument
MethodHandle insertArguments(MethodHandle target, int pos, Object... values)MethodHandle square = MethodHandles.insertArguments(power, 1, 2);System.out.println(square.invoke(new BigDecimal(5)));
Like currying,where parameters are bound resulting in a new method
What is invokedynamic support?
Introduced in Java 7 to support dynamic method invocation
Primarily for dynamic language designers that create Java bytecode, not Java programmers
Currently not used by Java compiler, but will be in Java 8 with lambda expressions
Consists of a new invokedynamic bytecode and the means for determining at runtime what functionality should be executed when a method is invoked
How is a method invoked using invokdynamic?
invokedynamic bytecode instruction writing to class file when method is dynamic invoked
Argument to invokedynamic instruction is a reference to a bootstrap method that has been written to a special place in the class file
Bootstrap method creates a CallSite instance that can be used at runtime to execute appropriate method
What is a CallSite?
Where method handles come into play with invokedynamic support
CallSite instance created by the bootstrap method that is associated with the invokedynamic instruction
CallSite instance holds a method handle reference (the target) which is invoked by the JVM at runtime
At runtime when the JVM encounters an invokedynamic instruction, it invokes the MethodHandle target associated with the CallSite instance
Runtime dynamic method invocation
What is a lambda expression?
Introduced in Java 8 JSR 335
Represents a block of functionality that can be executed and referenced
Anonymous method
Similar to a closure in other languages, but only allows reference to effectively final (variables declared final or not reassigned) from surrounding scope
Treated by the runtime as an instance of a special type of interface called a functional interface
How is a lambda expression defined?
Syntax is: ->
Parameters are optionally typed
If type omitted it will be inferred by the compiler from the declaration context
Parameter list must be surrounded by parentheses if more than one parameter or explicitly typed
Body is a single expression or a block of statements
Single expression doesn't require braces or an explicit return
Return required if braces used for body
Lambda Expression Examples
() -> System.out.println(Hello!)n -> n > 5(int n) -> n > 5(n) -> {return n > 5;}(a,b) -> Integer.compare(a,b)(a,b) -> {return Integer.compare(a,b);}
What is the type of a lambda expression?
Lamba expressions are like regular Java expressions and have a type
Their type is inferred from the surrounding context by the compiler, called the target type
Lambda expressions can only appear in context where target type is a functional interface
So lambda expressions are represented at runtime by functional interfaces
What is a functional interface?
Interface with a single abstract method
Runnable and Comparator are examples
Package java.util.function contains over 40 functional interfaces
Examples from this package include:Consumer - accepts single input argument and returns no result
Predicate - accepts single input argument and returns boolean result
Lambda expressions and target type
Lambda expressions are implemented using the functional interface target type to infer parameter types and the return type of the lambda expression
This is why lambda expressions don't require explicitly typed parameters or a return type, they can be inferred from target type by the compiler
Target Type Examples
IntPredicate p = n -> n > 5;p.test(4);
Comparator c =(a,b) -> Integer.compare(a,b);c.compare(1,2);
Runnable r = () -> System.out.println(Hello!)r.run();
How are lambda expressions implemented?
invokedynamic is used to allow flexibility of lambda expression implementation
Allows selection of translation strategy to be deferred until runtime
When compiler encounters lambda expression, lambda is 'desugared' into a private static method whose parameter types and return type match that of the functional target type
This method is called by the instance of the functional target type that is generated by the invokedynamic instruction
'Desugaring' Example
IntPredicate p = n -> n > 5;IntPredicate has one method, test that takes an int argument and returns a booleanCompiler creates private static method within the class that contains the lambda expressionprivate static boolean lambda$0(int n) { return n > 5;}Method parameters and return type determined from IntPredicate.test method parameters and return type
The lambda invokedyanmic instruction
The compiler generates an invokedynamic instruction at the point in the code where the lambda expression appears
When invoked, the instruction returns an instance of the functional interface
Dynamic arguments to invokedynamic instruction (those passed to bootstrap method) are values captured from lexical scope
The lambda bootstrap method
Bootstrap method associated with the generated invokedynamic instruction is the method LambdaMethodFactory.metafactory
Takes information about target type and the lambda implementation (desugared) method and generates a CallSite instance that is linked to the invokedynamic instruction
The generated CallSite instance
CallSite generated by the bootstrap method has an associated MethodHandle target that when invoked returns an instance of the functional interface target type associated with the lambda expression
The single method of the returned instance calls the 'desugared' generated method
To summarize at compile-time...
Compiler encounters lambda expression
Compiler determines functional interface target type from context
Compiler generates desugared lambda method
Compiler indicates bootstrap method and provides static arguments about lambda known at compile-time (target type, method handle for desugared lambda, etc.)
Compiler generates invokedynamic instruction referencing bootstrap method
Some javap output
import java.util.function.*;
public class Lambda1 { public static void main(String[] args) { IntPredicate p = n -> n > 5; }}
How are lambda expressions used?
Often used in conjunction with collections and iterators
Also used with event listeners for callbacks
ExamplesList list = Arrays.asList(1,5,4,3,7);
Collections.sort(list, (a,b) -> Integer.compare(a,b));
list.forEach(n -> System.out.println(n));
A Few Additional Java 8 Features
Method referencesAllows a method to be used like a lambda expression
Lambdas define the function body, method references refer to an existing method by name
Kind of like shorthand for a lambda expression that just invokes the named method with the lambda arguments
Kinds of method referencesStatic method (className::methodName)
Instance method (instanceRef::methodName)
Constructor (className::new)
Method Reference Examples
// static method referenceFunction hexMe = Integer::toHexString;hexMe.apply(10);
// instance method referenceString s = "Test it";Predicate m = s::startsWith;m.test("T");
A Few Additional Java 8 Features (cont.)
Default interface methodsAllow interfaces to evolve
Concrete behavior that is added to an interface
Methods of interface are either default or abstract
Default methods have an implementation that is inherited by implementing classes
Don't count towards 'one abstract method' rule of functional interfaces
Can be overridden
Default Method Examples
IterableforEach(Consumer