Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Java MethodHandle.invokeExact: make the call-site type part of the contract

Last updated: 7 Oct 20265 min read
tutorial
AdvancedBy AITrove Editorial

MethodHandle.invokeExact requires the call site's argument and return types to match the handle's MethodType exactly; a mismatch raises WrongMethodTypeException.

Operational contract

The sample caches a public String.substring handle with receiver String and two int arguments. Its cast to String establishes the return type of the invokeExact call site. A Long argument in place of int, or discarding the return value, changes the call-site type and fails; invoke is the adapting form when conversions are deliberate. The handle is resolved once and its lookup obeys access rules. Index validation belongs to the business boundary, not to MethodHandle, so this method checks the requested slice first.

Failure case

A receipt code is sliced from index 8 to 10. The result is 47. A refactor that changes one index to long without changing the handle type fails at the exact invocation boundary rather than silently choosing a different overload.

Java code

Java
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Objects;

public class ReceiptCodeSlice {
    private static final MethodHandle SLICE = findSlice();

    private static MethodHandle findSlice() {
        try {
            return MethodHandles.publicLookup().findVirtual(String.class,
                    "substring", MethodType.methodType(String.class, int.class, int.class));
        } catch (ReflectiveOperationException failure) {
            throw new ExceptionInInitializerError(failure);
        }
    }

    public static String read(String receiptCode, int start, int end) throws Throwable {
        Objects.requireNonNull(receiptCode);
        if (start < 0 || end < start || end > receiptCode.length())
            throw new IllegalArgumentException("Invalid receipt-code slice");
        return (String) SLICE.invokeExact(receiptCode, start, end);
    }
}

Performance and ownership cost

The cached lookup is paid once per class initialization. Each invocation adds method-handle dispatch and substring's O(L) copy for L selected characters, with O(L) new string storage. Wrong call-site types are contract failures, not a fallback lookup mechanism.

Common Mistakes

  • Do not confuse invokeExact with the adapting invoke call.
  • Do not omit the return cast when it defines the expected call-site type.
  • Do not assume a handle bypasses public-lookup access rules or input range validation.

Connected lessons

java
reflective invocation
methodhandle-exact-callsite
Storage details