Working with Method Handles
1. Understanding MethodHandle API
| Concept | Detail |
| Class | java.lang.invoke.MethodHandle |
| Created by | MethodHandles.Lookup |
| Typed | Carries MethodType |
| Backed by | invokedynamic infrastructure |
2. Creating MethodHandles
| Lookup | For |
findVirtual | Instance method |
findStatic | Static method |
findConstructor | Constructor |
findGetter / findSetter | Field |
findSpecial | super-call |
3. Invoking MethodHandles
| Method | Type Check |
invokeExact(args) | Strict — exact type match |
invoke(args) | Adapts via casts/conversions |
invokeWithArguments(Object...) | Reflective-style |
Warning: invokeExact requires the call site descriptor to match exactly — a return type or arg mismatch throws WrongMethodTypeException.
4. Using Method Types (MethodType)
| Factory | Result |
methodType(rt) | No params |
methodType(rt, p1, p2) | With params |
methodType(rt, paramsList) | From list |
changeReturnType / appendParameterTypes | Mutate |
5. Binding Methods (bindTo)
| Adapter | Effect |
bindTo(receiver) | Curry first arg |
insertArguments(pos, vals) | Insert constant args |
dropArguments(pos, types) | Ignore extra args |
asType(MethodType) | Cast/convert |
asSpreader / asCollector | Array spread |
6. Creating Dynamic Call Sites
| Type | Use |
ConstantCallSite | Fixed target |
MutableCallSite | Reassignable |
VolatileCallSite | Thread-safe reassign |
7. Understanding invokedynamic Instruction
invokedynamic
→ bootstrap method (one-time)
→ returns CallSite (with MethodHandle target)
→ subsequent calls go directly to target
| Use | Example |
| Lambda creation | LambdaMetafactory |
| String concat | StringConcatFactory (Java 9+) |
| Switch on patterns | Java 21+ |
8. Comparing MethodHandle vs Reflection
| Feature | Reflection | MethodHandle |
| Speed | Slow (boxing, checks) | Near direct call |
| Access check | Per call | At lookup only |
| Type safety | Object[] | MethodType-checked |
| JIT optimization | Limited | Inlined when constant |
| Pattern | Trick |
| Static final | Allows JIT constant folding |
invokeExact | Avoids type adaptation |
| LambdaMetafactory | Build typed FI implementations |
| Hot path | Cache MethodHandle in static field |
Example: Generated FI
MethodHandles.Lookup lk = MethodHandles.lookup();
MethodHandle target = lk.findVirtual(String.class, "length", MethodType.methodType(int.class));
CallSite site = LambdaMetafactory.metafactory(lk, "applyAsInt",
MethodType.methodType(ToIntFunction.class),
MethodType.methodType(int.class, Object.class),
target,
MethodType.methodType(int.class, String.class));
ToIntFunction<String> f = (ToIntFunction<String>) site.getTarget().invokeExact();
10. Using VarHandle for Field Access
| API | Use |
MethodHandles.lookup().findVarHandle(cls, "field", T.class) | Instance field |
findStaticVarHandle | Static field |
arrayElementVarHandle(int[].class) | Array element |
| Atomic ops | compareAndSet, getAndAdd, getVolatile |