Package Summary  Overview Summary

class:MethodHandles [NONE]



  • public class MethodHandles
    extends Object
    
    This class consists exclusively of static methods that operate on or return method handles. They fall into several categories:
    • Lookup methods which help create method handles for methods and fields.
    • Combinator methods, which combine or transform pre-existing method handles into new ones.
    • Other factory methods to create method handles that emulate other common JVM operations or control flow patterns.
    Since:
    1.7

method:lookup() [NONE]

  • lookup

    public static MethodHandles.Lookup lookup()
    Returns a lookup object with full capabilities to emulate all supported bytecode behaviors of the caller. These capabilities include private access to the caller. Factory methods on the lookup object can create direct method handles for any member that the caller has access to via bytecodes, including protected and private fields and methods. This lookup object is a capability which may be delegated to trusted agents. Do not store it in place where untrusted code can access it.

    This method is caller sensitive, which means that it may return different values to different callers.

    For any given caller class C, the lookup object returned by this call has equivalent capabilities to any lookup object supplied by the JVM to the bootstrap method of an invokedynamic instruction executing in the same caller class C.

    Returns:
    a lookup object for the caller of this method, with private access

method:publicLookup() [CHANGED]

  • publicLookup

    public static MethodHandles.Lookup publicLookup()
    Returns a lookup object which is trusted minimally. It can only be used to create method handles to publicly accessible fields and methods.

    As a matter of pure convention, the lookup class of this lookup object will be Object. Consequently, the lookup context of this lookup object will be the bootstrap class loader, which means it cannot find user classes.

    Discussion: The lookup class can be changed to any other class C using an expression of the form publicLookup().in(C.class). Since all classes have equal access to public names, such a change would confer no new access rights, but may change the lookup context by virtue of changing the class loader. A public lookup object is always subject to security manager checks . Also, it cannot access caller sensitive methods .

    Returns:
    a lookup object which is trusted minimally
  • publicLookup

    public static MethodHandles.Lookup publicLookup()
    Returns a lookup object which is trusted minimally. It can only be used to create method handles to publicly accessible fields and methods.

    As a matter of pure convention, the lookup class of this lookup object will be Object. Consequently, the lookup context of this lookup object will be the bootstrap class loader, which means it cannot find user classes.

    Discussion: The lookup class can be changed to any other class C using an expression of the form publicLookup().in(C.class). Since all classes have equal access to public names, such a change would confer no new access rights, but may change the lookup context by virtue of changing the class loader. A public lookup object is always subject to security manager checks . Also, it cannot access caller sensitive methods .

    Returns:
    a lookup object which is trusted minimally
  • publicLookup

    public static MethodHandles.Lookup publicLookup()
    Returns a lookup object which is trusted minimally. It can only be used to create method handles to publicly accessible fields and methods.

    As a matter of pure convention, the lookup class of this lookup object will be Object.

    Discussion: The lookup class can be changed to any other class C using an expression of the form publicLookup().in(C.class). Since all classes have equal access to public names, such a change would confer no new access rights. A public lookup object is always subject to security manager checks . Also, it cannot access caller sensitive methods .

    Returns:
    a lookup object which is trusted minimally

method:reflectAs(java.lang.Class, java.lang.invoke.MethodHandle) [NONE]

  • reflectAs

    public static <T extends Member> T reflectAs(Class<T> expected,
                                                 MethodHandle target)
    Performs an unchecked "crack" of a direct method handle . The result is as if the user had obtained a lookup object capable enough to crack the target method handle, called Lookup.revealDirect on the target to obtain its symbolic reference, and then called MethodHandleInfo.reflectAs to resolve the symbolic reference to a member.

    If there is a security manager, its checkPermission method is called with a ReflectPermission("suppressAccessChecks") permission.

    Type Parameters:
    T - the desired type of the result, either Member or a subtype
    Parameters:
    target - a direct method handle to crack into symbolic reference components
    expected - a class object representing the desired result type T
    Returns:
    a reference to the method, constructor, or field object
    Throws:
    SecurityException - if the caller is not privileged to call setAccessible
    NullPointerException - if either argument is null
    IllegalArgumentException - if the target is not a direct method handle
    ClassCastException - if the member is not of the expected type
    Since:
    1.8

method:arrayElementGetter(java.lang.Class) [NONE]

  • arrayElementGetter

    public static MethodHandle arrayElementGetter(Class<?> arrayClass)
                                           throws IllegalArgumentException
    
    Produces a method handle giving read access to elements of an array. The type of the method handle will have a return type of the array's element type. Its first argument will be the array type, and the second will be int.
    Parameters:
    arrayClass - an array type
    Returns:
    a method handle which can load values from the given array type
    Throws:
    NullPointerException - if the argument is null
    IllegalArgumentException - if arrayClass is not an array type

method:arrayElementSetter(java.lang.Class) [NONE]

  • arrayElementSetter

    public static MethodHandle arrayElementSetter(Class<?> arrayClass)
                                           throws IllegalArgumentException
    
    Produces a method handle giving write access to elements of an array. The type of the method handle will have a void return type. Its last argument will be the array's element type. The first and second arguments will be the array type and int.
    Parameters:
    arrayClass - the class of an array
    Returns:
    a method handle which can store values into the array type
    Throws:
    NullPointerException - if the argument is null
    IllegalArgumentException - if arrayClass is not an array type

method:arrayElementVarHandle(java.lang.Class) [ADDED]

  • arrayElementVarHandle

    public static VarHandle arrayElementVarHandle(Class<?> arrayClass)
                                           throws IllegalArgumentException
    
    Produces a VarHandle giving access to elements of an array type T[], supporting shape (T[], int : T) .

    Certain access modes of the returned VarHandle are unsupported under the following conditions:

    • if the component type is anything other than int, long or a reference type, then atomic update access modes are unsupported. (Future major platform releases of the JDK may support additional types for certain currently unsupported access modes.)
    • if the component type is anything other than int or long, then numeric atomic update access modes are unsupported. (Future major platform releases of the JDK may support additional numeric types for certain currently unsupported access modes.)

    Parameters:
    arrayClass - the class of an array, of type T[]
    Returns:
    a VarHandle giving access to elements of an array
    Throws:
    NullPointerException - if the arrayClass is null
    IllegalArgumentException - if arrayClass is not an array type
    Since:
    9

method:byteArrayViewVarHandle(java.lang.Class, boolean) [ADDED]

  • byteArrayViewVarHandle

    public static VarHandle byteArrayViewVarHandle(Class<?> viewArrayClass,
                                                   boolean bigEndian)
                                            throws IllegalArgumentException
    
    Produces a VarHandle giving access to elements of a byte[] array viewed as if it were a different primitive array type, such as int[] or long[]. The shape of the resulting VarHandle is (byte[], int : T) , where the int coordinate type corresponds to an argument that is an index in a byte[] array, and T is the component type of the given view array class. The returned VarHandle accesses bytes at an index in a byte[] array, composing bytes to or from a value of T according to the given endianness.

    The supported component types (variables types) are short, char, int, long, float and double.

    Access of bytes at a given index will result in an IndexOutOfBoundsException if the index is less than 0 or greater than the byte[] array length minus the size (in bytes) of T.

    Access of bytes at an index may be aligned or misaligned for T, with respect to the underlying memory address, A say, associated with the array and index. If access is misaligned then access for anything other than the get and set access modes will result in an IllegalStateException. In such cases atomic access is only guaranteed with respect to the largest power of two that divides the GCD of A and the size (in bytes) of T. If access is aligned then following access modes are supported and are guaranteed to support atomic access:

    • read write access modes for all T;
    • atomic update access modes for int, long, float or double. (Future major platform releases of the JDK may support additional types for certain currently unsupported access modes.)
    • numeric atomic update access modes for int and long. (Future major platform releases of the JDK may support additional numeric types for certain currently unsupported access modes.)

    Misaligned access, and therefore atomicity guarantees, may be determined for byte[] arrays without operating on a specific array. Given an index, T and it's corresponding boxed type, T_BOX, misalignment may be determined as follows:

    
     int sizeOfT = T_BOX.BYTES;  // size in bytes of T
     int misalignedAtZeroIndex = ByteBuffer.wrap(new byte[0]).
         alignmentOffset(0, sizeOfT);
     int misalignedAtIndex = (misalignedAtZeroIndex + index) % sizeOfT;
     boolean isMisaligned = misalignedAtIndex != 0;
     
    

    Implementation Note:
    The variable types float and double are supported as if by transformation to and access with the variable types int and long respectively. For example, the transformation of a double value to a long value is performed as if using Double.doubleToRawLongBits(double), and the reverse transformation is performed as if using Double.longBitsToDouble(long).
    Parameters:
    viewArrayClass - the view array class, with a component type of type T
    bigEndian - true if the endianness of the view array elements, as stored in the underlying byte array, is big endian, otherwise little endian
    Returns:
    a VarHandle giving access to elements of a byte[] array viewed as if elements corresponding to the components type of the view array class
    Throws:
    NullPointerException - if viewArrayClass is null
    IllegalArgumentException - if viewArrayClass is not an array type
    UnsupportedOperationException - if the component type of viewArrayClass is not supported as a variable type
    Since:
    9

method:byteBufferViewVarHandle(java.lang.Class, boolean) [ADDED]

  • byteBufferViewVarHandle

    public static VarHandle byteBufferViewVarHandle(Class<?> viewArrayClass,
                                                    boolean bigEndian)
                                             throws IllegalArgumentException
    
    Produces a VarHandle giving access to elements of a ByteBuffer viewed as if it were an array of elements of a different primitive component type to that of byte, such as int[] or long[]. The shape of the resulting VarHandle is (ByteBuffer, int : T) , where the int coordinate type corresponds to an argument that is an index in a ByteBuffer, and T is the component type of the given view array class. The returned VarHandle accesses bytes at an index in a ByteBuffer, composing bytes to or from a value of T according to the given endianness.

    The supported component types (variables types) are short, char, int, long, float and double.

    Access will result in a ReadOnlyBufferException for anything other than the read access modes if the ByteBuffer is read-only.

    Access of bytes at a given index will result in an IndexOutOfBoundsException if the index is less than 0 or greater than the ByteBuffer limit minus the size (in bytes) of T.

    Access of bytes at an index may be aligned or misaligned for T, with respect to the underlying memory address, A say, associated with the ByteBuffer and index. If access is misaligned then access for anything other than the get and set access modes will result in an IllegalStateException. In such cases atomic access is only guaranteed with respect to the largest power of two that divides the GCD of A and the size (in bytes) of T. If access is aligned then following access modes are supported and are guaranteed to support atomic access:

    • read write access modes for all T;
    • atomic update access modes for int, long, float or double. (Future major platform releases of the JDK may support additional types for certain currently unsupported access modes.)
    • numeric atomic update access modes for int and long. (Future major platform releases of the JDK may support additional numeric types for certain currently unsupported access modes.)

    Misaligned access, and therefore atomicity guarantees, may be determined for a ByteBuffer, bb (direct or otherwise), an index, T and it's corresponding boxed type, T_BOX, as follows:

    
     int sizeOfT = T_BOX.BYTES;  // size in bytes of T
     ByteBuffer bb = ...
     int misalignedAtIndex = bb.alignmentOffset(index, sizeOfT);
     boolean isMisaligned = misalignedAtIndex != 0;
     
    

    Implementation Note:
    The variable types float and double are supported as if by transformation to and access with the variable types int and long respectively. For example, the transformation of a double value to a long value is performed as if using Double.doubleToRawLongBits(double), and the reverse transformation is performed as if using Double.longBitsToDouble(long).
    Parameters:
    viewArrayClass - the view array class, with a component type of type T
    bigEndian - true if the endianness of the view array elements, as stored in the underlying ByteBuffer, is big endian, otherwise little endian (Note this overrides the endianness of a ByteBuffer)
    Returns:
    a VarHandle giving access to elements of a ByteBuffer viewed as if elements corresponding to the components type of the view array class
    Throws:
    NullPointerException - if viewArrayClass is null
    IllegalArgumentException - if viewArrayClass is not an array type
    UnsupportedOperationException - if the component type of viewArrayClass is not supported as a variable type
    Since:
    9

method:spreadInvoker(java.lang.invoke.MethodType, int) [NONE]

  • spreadInvoker

    public static MethodHandle spreadInvoker(MethodType type,
                                             int leadingArgCount)
    Produces a method handle which will invoke any method handle of the given type, with a given number of trailing arguments replaced by a single trailing Object[] array. The resulting invoker will be a method handle with the following arguments:
    • a single MethodHandle target
    • zero or more leading values (counted by leadingArgCount)
    • an Object[] array containing trailing arguments

    The invoker will invoke its target like a call to invoke with the indicated type. That is, if the target is exactly of the given type, it will behave like invokeExact; otherwise it behave as if asType is used to convert the target to the required type.

    The type of the returned invoker will not be the given type, but rather will have all parameters except the first leadingArgCount replaced by a single array of type Object[], which will be the final parameter.

    Before invoking its target, the invoker will spread the final array, apply reference casts as necessary, and unbox and widen primitive arguments. If, when the invoker is called, the supplied array argument does not have the correct number of elements, the invoker will throw an IllegalArgumentException instead of invoking the target.

    This method is equivalent to the following code (though it may be more efficient):

    
    MethodHandle invoker = MethodHandles.invoker(type);
    int spreadArgCount = type.parameterCount() - leadingArgCount;
    invoker = invoker.asSpreader(Object[].class, spreadArgCount);
    return invoker;
     
    
    This method throws no reflective or security exceptions.
    Parameters:
    type - the desired target type
    leadingArgCount - number of fixed arguments, to be passed unchanged to the target
    Returns:
    a method handle suitable for invoking any method handle of the given type
    Throws:
    NullPointerException - if type is null
    IllegalArgumentException - if leadingArgCount is not in the range from 0 to type.parameterCount() inclusive, or if the resulting method handle's type would have too many parameters

method:exactInvoker(java.lang.invoke.MethodType) [NONE]

  • exactInvoker

    public static MethodHandle exactInvoker(MethodType type)
    Produces a special invoker method handle which can be used to invoke any method handle of the given type, as if by invokeExact. The resulting invoker will have a type which is exactly equal to the desired type, except that it will accept an additional leading argument of type MethodHandle.

    This method is equivalent to the following code (though it may be more efficient): publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)

    Discussion: Invoker method handles can be useful when working with variable method handles of unknown types. For example, to emulate an invokeExact call to a variable method handle M, extract its type T, look up the invoker method X for T, and call the invoker method, as X.invoke(T, A...) . (It would not work to call X.invokeExact, since the type T is unknown.) If spreading, collecting, or other argument transformations are required, they can be applied once to the invoker X and reused on many M method handle values, as long as they are compatible with the type of X.

    (Note: The invoker method is not available via the Core Reflection API. An attempt to call java.lang.reflect.Method.invoke on the declared invokeExact or invoke method will raise an UnsupportedOperationException.)

    This method throws no reflective or security exceptions.

    Parameters:
    type - the desired target type
    Returns:
    a method handle suitable for invoking any method handle of the given type
    Throws:
    IllegalArgumentException - if the resulting method handle's type would have too many parameters

method:invoker(java.lang.invoke.MethodType) [NONE]

  • invoker

    public static MethodHandle invoker(MethodType type)
    Produces a special invoker method handle which can be used to invoke any method handle compatible with the given type, as if by invoke. The resulting invoker will have a type which is exactly equal to the desired type, except that it will accept an additional leading argument of type MethodHandle.

    Before invoking its target, if the target differs from the expected type, the invoker will apply reference casts as necessary and box, unbox, or widen primitive values, as if by asType. Similarly, the return value will be converted as necessary. If the target is a variable arity method handle , the required arity conversion will be made, again as if by asType.

    This method is equivalent to the following code (though it may be more efficient): publicLookup().findVirtual(MethodHandle.class, "invoke", type)

    Discussion: A general method type is one which mentions only Object arguments and return values. An invoker for such a type is capable of calling any method handle of the same arity as the general type.

    (Note: The invoker method is not available via the Core Reflection API. An attempt to call java.lang.reflect.Method.invoke on the declared invokeExact or invoke method will raise an UnsupportedOperationException.)

    This method throws no reflective or security exceptions.

    Parameters:
    type - the desired target type
    Returns:
    a method handle suitable for invoking any method handle convertible to the given type
    Throws:
    IllegalArgumentException - if the resulting method handle's type would have too many parameters

method:varHandleExactInvoker(java.lang.invoke.VarHandle.AccessMode, java.lang.invoke.MethodType) [ADDED]

  • varHandleExactInvoker

    public static MethodHandle varHandleExactInvoker(VarHandle.AccessMode accessMode,
                                                     MethodType type)
    
    Produces a special invoker method handle which can be used to invoke a signature-polymorphic access mode method on any VarHandle whose associated access mode type is compatible with the given type. The resulting invoker will have a type which is exactly equal to the desired given type, except that it will accept an additional leading argument of type VarHandle.
    Parameters:
    accessMode - the VarHandle access mode
    type - the desired target type
    Returns:
    a method handle suitable for invoking an access mode method of any VarHandle whose access mode type is of the given type.
    Since:
    9

method:varHandleInvoker(java.lang.invoke.VarHandle.AccessMode, java.lang.invoke.MethodType) [ADDED]

  • varHandleInvoker

    public static MethodHandle varHandleInvoker(VarHandle.AccessMode accessMode,
                                                MethodType type)
    
    Produces a special invoker method handle which can be used to invoke a signature-polymorphic access mode method on any VarHandle whose associated access mode type is compatible with the given type. The resulting invoker will have a type which is exactly equal to the desired given type, except that it will accept an additional leading argument of type VarHandle.

    Before invoking its target, if the access mode type differs from the desired given type, the invoker will apply reference casts as necessary and box, unbox, or widen primitive values, as if by asType. Similarly, the return value will be converted as necessary.

    This method is equivalent to the following code (though it may be more efficient): publicLookup().findVirtual(VarHandle.class, accessMode.name(), type)

    Parameters:
    accessMode - the VarHandle access mode
    type - the desired target type
    Returns:
    a method handle suitable for invoking an access mode method of any VarHandle whose access mode type is convertible to the given type.
    Since:
    9

method:explicitCastArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType) [NONE]

  • explicitCastArguments

    public static MethodHandle explicitCastArguments(MethodHandle target,
                                                     MethodType newType)
    Produces a method handle which adapts the type of the given method handle to a new type by pairwise argument and return type conversion. The original type and new type must have the same number of arguments. The resulting method handle is guaranteed to report a type which is equal to the desired new type.

    If the original type and new type are equal, returns target.

    The same conversions are allowed as for MethodHandle.asType, and some additional conversions are also applied if those conversions fail. Given types T0, T1, one of the following conversions is applied if possible, before or instead of any conversions done by asType:

    • If T0 and T1 are references, and T1 is an interface type, then the value of type T0 is passed as a T1 without a cast. (This treatment of interfaces follows the usage of the bytecode verifier.)
    • If T0 is boolean and T1 is another primitive, the boolean is converted to a byte value, 1 for true, 0 for false. (This treatment follows the usage of the bytecode verifier.)
    • If T1 is boolean and T0 is another primitive, T0 is converted to byte via Java casting conversion (JLS 5.5), and the low order bit of the result is tested, as if by (x & 1) != 0 .
    • If T0 and T1 are primitives other than boolean, then a Java casting conversion (JLS 5.5) is applied. (Specifically, T0 will convert to T1 by widening and/or narrowing.)
    • If T0 is a reference and T1 a primitive, an unboxing conversion will be applied at runtime, possibly followed by a Java casting conversion (JLS 5.5) on the primitive value, possibly followed by a conversion from byte to boolean by testing the low-order bit.
    • If T0 is a reference and T1 a primitive, and if the reference is null at runtime, a zero value is introduced.

    Parameters:
    target - the method handle to invoke after arguments are retyped
    newType - the expected type of the new method handle
    Returns:
    a method handle which delegates to the target after performing any necessary argument conversions, and arranges for any necessary return value conversions
    Throws:
    NullPointerException - if either argument is null
    WrongMethodTypeException - if the conversion cannot be made
    See Also:
    MethodHandle.asType(java.lang.invoke.MethodType)

method:permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...) [NONE]

  • permuteArguments

    public static MethodHandle permuteArguments(MethodHandle target,
                                                MethodType newType,
                                                int... reorder)
    Produces a method handle which adapts the calling sequence of the given method handle to a new type, by reordering the arguments. The resulting method handle is guaranteed to report a type which is equal to the desired new type.

    The given array controls the reordering. Call #I the number of incoming parameters (the value newType.parameterCount(), and call #O the number of outgoing parameters (the value target.type().parameterCount()). Then the length of the reordering array must be #O, and each element must be a non-negative number less than #I. For every N less than #O, the N-th outgoing argument will be taken from the I-th incoming argument, where I is reorder[N].

    No argument or return value conversions are applied. The type of each incoming argument, as determined by newType, must be identical to the type of the corresponding outgoing parameter or parameters in the target method handle. The return type of newType must be identical to the return type of the original target.

    The reordering array need not specify an actual permutation. An incoming argument will be duplicated if its index appears more than once in the array, and an incoming argument will be dropped if its index does not appear in the array. As in the case of dropArguments, incoming arguments which are not mentioned in the reordering array may be of any type, as determined only by newType.

    
    import static java.lang.invoke.MethodHandles.*;
    import static java.lang.invoke.MethodType.*;
    ...
    MethodType intfn1 = methodType(int.class, int.class);
    MethodType intfn2 = methodType(int.class, int.class, int.class);
    MethodHandle sub = ... (int x, int y) -> (x-y) ...;
    assert(sub.type().equals(intfn2));
    MethodHandle sub1 = permuteArguments(sub, intfn2, 0, 1);
    MethodHandle rsub = permuteArguments(sub, intfn2, 1, 0);
    assert((int)rsub.invokeExact(1, 100) == 99);
    MethodHandle add = ... (int x, int y) -> (x+y) ...;
    assert(add.type().equals(intfn2));
    MethodHandle twice = permuteArguments(add, intfn1, 0, 0);
    assert(twice.type().equals(intfn1));
    assert((int)twice.invokeExact(21) == 42);
     
    

    Note: The resulting adapter is never a variable-arity method handle , even if the original target method handle was.

    Parameters:
    target - the method handle to invoke after arguments are reordered
    newType - the expected type of the new method handle
    reorder - an index array which controls the reordering
    Returns:
    a method handle which delegates to the target after it drops unused arguments and moves and/or duplicates the other arguments
    Throws:
    NullPointerException - if any argument is null
    IllegalArgumentException - if the index array length is not equal to the arity of the target, or if any index array element not a valid index for a parameter of newType, or if two corresponding parameter types in target.type() and newType are not identical,

method:constant(java.lang.Class, java.lang.Object) [NONE]

  • constant

    public static MethodHandle constant(Class<?> type,
                                        Object value)
    Produces a method handle of the requested return type which returns the given constant value every time it is invoked.

    Before the method handle is returned, the passed-in value is converted to the requested type. If the requested type is primitive, widening primitive conversions are attempted, else reference conversions are attempted.

    The returned method handle is equivalent to identity(type).bindTo(value).

    Parameters:
    type - the return type of the desired method handle
    value - the value to return
    Returns:
    a method handle of the given return type and no arguments, which always returns the given value
    Throws:
    NullPointerException - if the type argument is null
    ClassCastException - if the value cannot be converted to the required return type
    IllegalArgumentException - if the given type is void.class

method:identity(java.lang.Class) [NONE]

  • identity

    public static MethodHandle identity(Class<?> type)
    Produces a method handle which returns its sole argument when invoked.
    Parameters:
    type - the type of the sole parameter and return value of the desired method handle
    Returns:
    a unary method handle which accepts and returns the given type
    Throws:
    NullPointerException - if the argument is null
    IllegalArgumentException - if the given type is void.class

method:insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...) [NONE]

  • insertArguments

    public static MethodHandle insertArguments(MethodHandle target,
                                               int pos,
                                               Object... values)
    Provides a target method handle with one or more bound arguments in advance of the method handle's invocation. The formal parameters to the target corresponding to the bound arguments are called bound parameters . Returns a new method handle which saves away the bound arguments. When it is invoked, it receives arguments for any non-bound parameters, binds the saved arguments to their corresponding parameters, and calls the original target.

    The type of the new method handle will drop the types for the bound parameters from the original target type, since the new method handle will no longer require those arguments to be supplied by its callers.

    Each given argument object must match the corresponding bound parameter type. If a bound parameter type is a primitive, the argument object must be a wrapper, and will be unboxed to produce the primitive value.

    The pos argument selects which parameters are to be bound. It may range between zero and N-L (inclusively), where N is the arity of the target method handle and L is the length of the values array.

    Note: The resulting adapter is never a variable-arity method handle , even if the original target method handle was.

    Parameters:
    target - the method handle to invoke after the argument is inserted
    pos - where to insert the argument (zero for the first)
    values - the series of arguments to insert
    Returns:
    a method handle which inserts an additional argument, before calling the original method handle
    Throws:
    NullPointerException - if the target or the values array is null
    See Also:
    MethodHandle.bindTo(java.lang.Object)

method:dropArguments(java.lang.invoke.MethodHandle, int, java.util.List) [NONE]

  • dropArguments

    public static MethodHandle dropArguments(MethodHandle target,
                                             int pos,
                                             List<Class<?>> valueTypes)
    Produces a method handle which will discard some dummy arguments before calling some other specified target method handle. The type of the new method handle will be the same as the target's type, except it will also include the dummy argument types, at some given position.

    The pos argument may range between zero and N, where N is the arity of the target. If pos is zero, the dummy arguments will precede the target's real arguments; if pos is N they will come after.

    Example:

    
    import static java.lang.invoke.MethodHandles.*;
    import static java.lang.invoke.MethodType.*;
    ...
    MethodHandle cat = lookup().findVirtual(String.class,
      "concat", methodType(String.class, String.class));
    assertEquals("xy", (String) cat.invokeExact("x", "y"));
    MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class);
    MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));
    assertEquals(bigType, d0.type());
    assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
     
    

    This method is also equivalent to the following code:

     
    
    dropArguments(target, pos, valueTypes.toArray(new Class[0]))
     
    
    
    Parameters:
    target - the method handle to invoke after the arguments are dropped
    valueTypes - the type(s) of the argument(s) to drop
    pos - position of first argument to drop (zero for the leftmost)
    Returns:
    a method handle which drops arguments of the given types, before calling the original method handle
    Throws:
    NullPointerException - if the target is null, or if the valueTypes list or any of its elements is null
    IllegalArgumentException - if any element of valueTypes is void.class, or if pos is negative or greater than the arity of the target, or if the new method handle's type would have too many parameters

method:dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class...) [NONE]

  • dropArguments

    public static MethodHandle dropArguments(MethodHandle target,
                                             int pos,
                                             Class<?>... valueTypes)
    Produces a method handle which will discard some dummy arguments before calling some other specified target method handle. The type of the new method handle will be the same as the target's type, except it will also include the dummy argument types, at some given position.

    The pos argument may range between zero and N, where N is the arity of the target. If pos is zero, the dummy arguments will precede the target's real arguments; if pos is N they will come after.

    Example:

    
    import static java.lang.invoke.MethodHandles.*;
    import static java.lang.invoke.MethodType.*;
    ...
    MethodHandle cat = lookup().findVirtual(String.class,
      "concat", methodType(String.class, String.class));
    assertEquals("xy", (String) cat.invokeExact("x", "y"));
    MethodHandle d0 = dropArguments(cat, 0, String.class);
    assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
    MethodHandle d1 = dropArguments(cat, 1, String.class);
    assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
    MethodHandle d2 = dropArguments(cat, 2, String.class);
    assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
    MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
    assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
     
    

    This method is also equivalent to the following code:

     
    
    dropArguments(target, pos, Arrays.asList(valueTypes))
     
    
    
    Parameters:
    target - the method handle to invoke after the arguments are dropped
    valueTypes - the type(s) of the argument(s) to drop
    pos - position of first argument to drop (zero for the leftmost)
    Returns:
    a method handle which drops arguments of the given types, before calling the original method handle
    Throws:
    NullPointerException - if the target is null, or if the valueTypes array or any of its elements is null
    IllegalArgumentException - if any element of valueTypes is void.class, or if pos is negative or greater than the arity of the target, or if the new method handle's type would have too many parameters

method:filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...) [NONE]

  • filterArguments

    public static MethodHandle filterArguments(MethodHandle target,
                                               int pos,
                                               MethodHandle... filters)
    Adapts a target method handle by pre-processing one or more of its arguments, each with its own unary filter function, and then calling the target with each pre-processed argument replaced by the result of its corresponding filter function.

    The pre-processing is performed by one or more method handles, specified in the elements of the filters array. The first element of the filter array corresponds to the pos argument of the target, and so on in sequence.

    Null arguments in the array are treated as identity functions, and the corresponding arguments left unchanged. (If there are no non-null elements in the array, the original target is returned.) Each filter is applied to the corresponding argument of the adapter.

    If a filter F applies to the Nth argument of the target, then F must be a method handle which takes exactly one argument. The type of F's sole argument replaces the corresponding argument type of the target in the resulting adapted method handle. The return type of F must be identical to the corresponding parameter type of the target.

    It is an error if there are elements of filters (null or not) which do not correspond to argument positions in the target.

    Example:

    
    import static java.lang.invoke.MethodHandles.*;
    import static java.lang.invoke.MethodType.*;
    ...
    MethodHandle cat = lookup().findVirtual(String.class,
      "concat", methodType(String.class, String.class));
    MethodHandle upcase = lookup().findVirtual(String.class,
      "toUpperCase", methodType(String.class));
    assertEquals("xy", (String) cat.invokeExact("x", "y"));
    MethodHandle f0 = filterArguments(cat, 0, upcase);
    assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy
    MethodHandle f1 = filterArguments(cat, 1, upcase);
    assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
    MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
    assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
     
    

    Here is pseudocode for the resulting adapter. In the code, T denotes the return type of both the target and resulting adapter. P/p and B/b represent the types and values of the parameters and arguments that precede and follow the filter position pos, respectively. A[i]/a[i] stand for the types and values of the filtered parameters and arguments; they also represent the return types of the filter[i] handles. The latter accept arguments v[i] of type V[i], which also appear in the signature of the resulting adapter.

    
     T target(P... p, A[i]... a[i], B... b);
     A[i] filter[i](V[i]);
     T adapter(P... p, V[i]... v[i], B... b) {
       return target(p..., filter[i](v[i])..., b...);
     }
     
    

    Note: The resulting adapter is never a variable-arity method handle , even if the original target method handle was.

    Parameters:
    target - the method handle to invoke after arguments are filtered
    pos - the position of the first argument to filter
    filters - method handles to call initially on filtered arguments
    Returns:
    method handle which incorporates the specified argument filtering logic
    Throws:
    NullPointerException - if the target is null or if the filters array is null
    IllegalArgumentException - if a non-null element of filters does not match a corresponding argument type of target as described above, or if the pos+filters.length is greater than target.type().parameterCount(), or if the resulting method handle's type would have too many parameters

method:collectArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle) [NONE]

  • collectArguments

    public static MethodHandle collectArguments(MethodHandle target,
                                                int pos,
                                                MethodHandle filter)
    Adapts a target method handle by pre-processing a sub-sequence of its arguments with a filter (another method handle). The pre-processed arguments are replaced by the result (if any) of the filter function. The target is then called on the modified (usually shortened) argument list.

    If the filter returns a value, the target must accept that value as its argument in position pos, preceded and/or followed by any arguments not passed to the filter. If the filter returns void, the target must accept all arguments not passed to the filter. No arguments are reordered, and a result returned from the filter replaces (in order) the whole subsequence of arguments originally passed to the adapter.

    The argument types (if any) of the filter replace zero or one argument types of the target, at position pos, in the resulting adapted method handle. The return type of the filter (if any) must be identical to the argument type of the target at position pos, and that target argument is supplied by the return value of the filter.

    In all cases, pos must be greater than or equal to zero, and pos must also be less than or equal to the target's arity.

    Example:

    
    import static java.lang.invoke.MethodHandles.*;
    import static java.lang.invoke.MethodType.*;
    ...
    MethodHandle deepToString = publicLookup()
      .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
    
    MethodHandle ts1 = deepToString.asCollector(String[].class, 1);
    assertEquals("[strange]", (String) ts1.invokeExact("strange"));
    
    MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
    assertEquals("[up, down]", (String) ts2.invokeExact("up", "down"));
    
    MethodHandle ts3 = deepToString.asCollector(String[].class, 3);
    MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2);
    assertEquals("[top, [up, down], strange]",
                 (String) ts3_ts2.invokeExact("top", "up", "down", "strange"));
    
    MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1);
    assertEquals("[top, [up, down], [strange]]",
                 (String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange"));
    
    MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3);
    assertEquals("[top, [[up, down, strange], charm], bottom]",
                 (String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));
     
    

    Here is pseudocode for the resulting adapter. In the code, T represents the return type of the target and resulting adapter. V/v stand for the return type and value of the filter, which are also found in the signature and arguments of the target, respectively, unless V is void. A/a and C/c represent the parameter types and values preceding and following the collection position, pos, in the target's signature. They also turn up in the resulting adapter's signature and arguments, where they surround B/b, which represent the parameter types and arguments to the filter (if any).

    
     T target(A...,V,C...);
     V filter(B...);
     T adapter(A... a,B... b,C... c) {
       V v = filter(b...);
       return target(a...,v,c...);
     }
     // and if the filter has no arguments:
     T target2(A...,V,C...);
     V filter2();
     T adapter2(A... a,C... c) {
       V v = filter2();
       return target2(a...,v,c...);
     }
     // and if the filter has a void return:
     T target3(A...,C...);
     void filter3(B...);
     T adapter3(A... a,B... b,C... c) {
       filter3(b...);
       return target3(a...,c...);
     }
     
    

    A collection adapter collectArguments(mh, 0, coll) is equivalent to one which first "folds" the affected arguments, and then drops them, in separate steps as follows:

    
     mh = MethodHandles.dropArguments(mh, 1, coll.type().parameterList()); //step 2
     mh = MethodHandles.foldArguments(mh, coll); //step 1
     
    
    If the target method handle consumes no arguments besides than the result (if any) of the filter coll, then collectArguments(mh, 0, coll) is equivalent to filterReturnValue(coll, mh) . If the filter method handle coll consumes one argument and produces a non-void result, then collectArguments(mh, N, coll) is equivalent to filterArguments(mh, N, coll) . Other equivalences are possible but would require argument permutation.

    Note: The resulting adapter is never a variable-arity method handle , even if the original target method handle was.

    Parameters:
    target - the method handle to invoke after filtering the subsequence of arguments
    pos - the position of the first adapter argument to pass to the filter, and/or the target argument which receives the result of the filter
    filter - method handle to call on the subsequence of arguments
    Returns:
    method handle which incorporates the specified argument subsequence filtering logic
    Throws:
    NullPointerException - if either argument is null
    IllegalArgumentException - if the return type of filter is non-void and is not the same as the pos argument of the target, or if pos is not between 0 and the target's arity, inclusive, or if the resulting method handle's type would have too many parameters
    See Also:
    foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) , filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...) , filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle)

method:filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) [NONE]

  • filterReturnValue

    public static MethodHandle filterReturnValue(MethodHandle target,
                                                 MethodHandle filter)
    Adapts a target method handle by post-processing its return value (if any) with a filter (another method handle). The result of the filter is returned from the adapter.

    If the target returns a value, the filter must accept that value as its only argument. If the target returns void, the filter must accept no arguments.

    The return type of the filter replaces the return type of the target in the resulting adapted method handle. The argument type of the filter (if any) must be identical to the return type of the target.

    Example:

    
    import static java.lang.invoke.MethodHandles.*;
    import static java.lang.invoke.MethodType.*;
    ...
    MethodHandle cat = lookup().findVirtual(String.class,
      "concat", methodType(String.class, String.class));
    MethodHandle length = lookup().findVirtual(String.class,
      "length", methodType(int.class));
    System.out.println((String) cat.invokeExact("x", "y")); // xy
    MethodHandle f0 = filterReturnValue(cat, length);
    System.out.println((int) f0.invokeExact("x", "y")); // 2
     
    

    Here is pseudocode for the resulting adapter. In the code, T/t represent the result type and value of the target; V, the result type of the filter; and A/a, the types and values of the parameters and arguments of the target as well as the resulting adapter.

    
     T target(A...);
     V filter(T);
     V adapter(A... a) {
       T t = target(a...);
       return filter(t);
     }
     // and if the target has a void return:
     void target2(A...);
     V filter2();
     V adapter2(A... a) {
       target2(a...);
       return filter2();
     }
     // and if the filter has a void return:
     T target3(A...);
     void filter3(V);
     void adapter3(A... a) {
       T t = target3(a...);
       filter3(t);
     }
     
    

    Note: The resulting adapter is never a variable-arity method handle , even if the original target method handle was.

    Parameters:
    target - the method handle to invoke before filtering the return value
    filter - method handle to call on the return value
    Returns:
    method handle which incorporates the specified return value filtering logic
    Throws:
    NullPointerException - if either argument is null
    IllegalArgumentException - if the argument list of filter does not match the return type of target as described above

method:foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) [NONE]

  • foldArguments

    public static MethodHandle foldArguments(MethodHandle target,
                                             MethodHandle combiner)
    Adapts a target method handle by pre-processing some of its arguments, and then calling the target with the result of the pre-processing, inserted into the original sequence of arguments.

    The pre-processing is performed by combiner, a second method handle. Of the arguments passed to the adapter, the first N arguments are copied to the combiner, which is then called. (Here, N is defined as the parameter count of the combiner.) After this, control passes to the target, with any result from the combiner inserted before the original N incoming arguments.

    If the combiner returns a value, the first parameter type of the target must be identical with the return type of the combiner, and the next N parameter types of the target must exactly match the parameters of the combiner.

    If the combiner has a void return, no result will be inserted, and the first N parameter types of the target must exactly match the parameters of the combiner.

    The resulting adapter is the same type as the target, except that the first parameter type is dropped, if it corresponds to the result of the combiner.

    (Note that dropArguments can be used to remove any arguments that either the combiner or the target does not wish to receive. If some of the incoming arguments are destined only for the combiner, consider using asCollector instead, since those arguments will not need to be live on the stack on entry to the target.)

    Example:

    
    import static java.lang.invoke.MethodHandles.*;
    import static java.lang.invoke.MethodType.*;
    ...
    MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
      "println", methodType(void.class, String.class))
        .bindTo(System.out);
    MethodHandle cat = lookup().findVirtual(String.class,
      "concat", methodType(String.class, String.class));
    assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
    MethodHandle catTrace = foldArguments(cat, trace);
    // also prints "boo":
    assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
     
    

    Here is pseudocode for the resulting adapter. In the code, T represents the result type of the target and resulting adapter. V/v represent the type and value of the parameter and argument of target that precedes the folding position; V also is the result type of the combiner. A/a denote the types and values of the N parameters and arguments at the folding position. B/b represent the types and values of the target parameters and arguments that follow the folded parameters and arguments.

    
     // there are N arguments in A...
     T target(V, A[N]..., B...);
     V combiner(A...);
     T adapter(A... a, B... b) {
       V v = combiner(a...);
       return target(v, a..., b...);
     }
     // and if the combiner has a void return:
     T target2(A[N]..., B...);
     void combiner2(A...);
     T adapter2(A... a, B... b) {
       combiner2(a...);
       return target2(a..., b...);
     }
     
    

    Note: The resulting adapter is never a variable-arity method handle , even if the original target method handle was.

    Parameters:
    target - the method handle to invoke after arguments are combined
    combiner - method handle to call initially on the incoming arguments
    Returns:
    method handle which incorporates the specified argument folding logic
    Throws:
    NullPointerException - if either argument is null
    IllegalArgumentException - if combiner's return type is non-void and not the same as the first argument type of the target, or if the initial N argument types of the target (skipping one matching the combiner's return type) are not identical with the argument types of combiner

method:guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) [NONE]

  • guardWithTest

    public static MethodHandle guardWithTest(MethodHandle test,
                                             MethodHandle target,
                                             MethodHandle fallback)
    Makes a method handle which adapts a target method handle, by guarding it with a test, a boolean-valued method handle. If the guard fails, a fallback handle is called instead. All three method handles must have the same corresponding argument and return types, except that the return type of the test must be boolean, and the test is allowed to have fewer arguments than the other two method handles.

    Here is pseudocode for the resulting adapter. In the code, T represents the uniform result type of the three involved handles; A/a, the types and values of the target parameters and arguments that are consumed by the test; and B/b, those types and values of the target parameters and arguments that are not consumed by the test.

    
     boolean test(A...);
     T target(A...,B...);
     T fallback(A...,B...);
     T adapter(A... a,B... b) {
       if (test(a...))
         return target(a..., b...);
       else
         return fallback(a..., b...);
     }
     
    
    Note that the test arguments (a... in the pseudocode) cannot be modified by execution of the test, and so are passed unchanged from the caller to the target or fallback as appropriate.
    Parameters:
    test - method handle used for test, must return boolean
    target - method handle to call if test passes
    fallback - method handle to call if test fails
    Returns:
    method handle which incorporates the specified if/then/else logic
    Throws:
    NullPointerException - if any argument is null
    IllegalArgumentException - if test does not return boolean, or if all three method types do not match (with the return type of test changed to match that of the target).

method:catchException(java.lang.invoke.MethodHandle, java.lang.Class, java.lang.invoke.MethodHandle) [NONE]

  • catchException

    public static MethodHandle catchException(MethodHandle target,
                                              Class<? extends Throwable> exType,
                                              MethodHandle handler)
    Makes a method handle which adapts a target method handle, by running it inside an exception handler. If the target returns normally, the adapter returns that value. If an exception matching the specified type is thrown, the fallback handle is called instead on the exception, plus the original arguments.

    The target and handler must have the same corresponding argument and return types, except that handler may omit trailing arguments (similarly to the predicate in guardWithTest). Also, the handler must have an extra leading parameter of exType or a supertype.

    Here is pseudocode for the resulting adapter. In the code, T represents the return type of the target and handler, and correspondingly that of the resulting adapter; A/a, the types and values of arguments to the resulting handle consumed by handler; and B/b, those of arguments to the resulting handle discarded by handler.

    
     T target(A..., B...);
     T handler(ExType, A...);
     T adapter(A... a, B... b) {
       try {
         return target(a..., b...);
       } catch (ExType ex) {
         return handler(ex, a...);
       }
     }
     
    
    Note that the saved arguments (a... in the pseudocode) cannot be modified by execution of the target, and so are passed unchanged from the caller to the handler, if the handler is invoked.

    The target and handler must return the same type, even if the handler always throws. (This might happen, for instance, because the handler is simulating a finally clause). To create such a throwing handler, compose the handler creation logic with throwException, in order to create a method handle of the correct return type.

    Parameters:
    target - method handle to call
    exType - the type of exception which the handler will catch
    handler - method handle to call if a matching exception is thrown
    Returns:
    method handle which incorporates the specified try/catch logic
    Throws:
    NullPointerException - if any argument is null
    IllegalArgumentException - if handler does not accept the given exception type, or if the method handle types do not match in their return types and their corresponding parameters
    See Also:
    tryFinally(MethodHandle, MethodHandle)

method:throwException(java.lang.Class, java.lang.Class) [NONE]

  • throwException

    public static MethodHandle throwException(Class<?> returnType,
                                              Class<? extends Throwable> exType)
    Produces a method handle which will throw exceptions of the given exType. The method handle will accept a single argument of exType, and immediately throw it as an exception. The method type will nominally specify a return of returnType. The return type may be anything convenient: It doesn't matter to the method handle's behavior, since it will never return normally.
    Parameters:
    returnType - the return type of the desired method handle
    exType - the parameter type of the desired method handle
    Returns:
    method handle which can throw the given exceptions
    Throws:
    NullPointerException - if either argument is null

method:loop(java.lang.invoke.MethodHandle[]...) [NONE]

  • loop

    public static MethodHandle loop(MethodHandle[]... clauses)
    Constructs a method handle representing a loop with several loop variables that are updated and checked upon each iteration. Upon termination of the loop due to one of the predicates, a corresponding finalizer is run and delivers the loop's result, which is the return value of the resulting handle.

    Intuitively, every loop is formed by one or more "clauses", each specifying a local iteration value and/or a loop exit. Each iteration of the loop executes each clause in order. A clause can optionally update its iteration variable; it can also optionally perform a test and conditional loop exit. In order to express this logic in terms of method handles, each clause will determine four actions:

    • Before the loop executes, the initialization of an iteration variable or loop invariant local.
    • When a clause executes, an update step for the iteration variable.
    • When a clause executes, a predicate execution to test for loop exit.
    • If a clause causes a loop exit, a finalizer execution to compute the loop's return value.

    Some of these clause parts may be omitted according to certain rules, and useful default behavior is provided in this case. See below for a detailed description.

    Each clause function, with the exception of clause initializers, is able to observe the entire loop state, because it will be passed all current iteration variable values, as well as all incoming loop parameters. Most clause functions will not need all of this information, but they will be formally connected as if by dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>) .

    Given a set of clauses, there is a number of checks and adjustments performed to connect all the parts of the loop. They are spelled out in detail in the steps below. In these steps, every occurrence of the word "must" corresponds to a place where IllegalArgumentException may be thrown if the required constraint is not met by the inputs to the loop combinator. The term "effectively identical", applied to parameter type lists, means that they must be identical, or else one list must be a proper prefix of the other.

    Step 0: Determine clause structure.

    1. The clause array (of type MethodHandle[][] must be non-null and contain at least one element.
    2. The clause array may not contain nulls or sub-arrays longer than four elements.
    3. Clauses shorter than four elements are treated as if they were padded by null elements to length four. Padding takes place by appending elements to the array.
    4. Clauses with all nulls are disregarded.
    5. Each clause is treated as a four-tuple of functions, called "init", "step", "pred", and "fini".

    Step 1A: Determine iteration variables.

    1. Examine init and step function return types, pairwise, to determine each clause's iteration variable type.
    2. If both functions are omitted, use void; else if one is omitted, use the other's return type; else use the common return type (they must be identical).
    3. Form the list of return types (in clause order), omitting all occurrences of void.
    4. This list of types is called the "common prefix".

    Step 1B: Determine loop parameters.

    • If at least one init function is given,
      1. Examine init function parameter lists.
      2. Omitted init functions are deemed to have null parameter lists.
      3. All init function parameter lists must be effectively identical.
      4. The longest parameter list (which is necessarily unique) is called the "common suffix".
    • If no init function is given,
      1. Examine the suffixes of the step, pred, and fini parameter lists, after removing the "common prefix".
      2. The longest of these suffixes is taken as the "common suffix".

    Step 1C: Determine loop return type.

    1. Examine fini function return types, disregarding omitted fini functions.
    2. If there are no fini functions, use void as the loop return type.
    3. Otherwise, use the common return type of the fini functions; they must all be identical.

    Step 1D: Check other types.

    1. There must be at least one non-omitted pred function.
    2. Every non-omitted pred function must have a boolean return type.

    Step 2: Determine parameter lists.

    1. The parameter list for the resulting loop handle will be the "common suffix".
    2. The parameter list for init functions will be adjusted to the "common suffix". (Note that their parameter lists are already effectively identical to the common suffix.)
    3. The parameter list for non-init (step, pred, and fini) functions will be adjusted to the common prefix followed by the common suffix, called the "common parameter sequence".
    4. Every non-init, non-omitted function parameter list must be effectively identical to the common parameter sequence.

    Step 3: Fill in omitted functions.

    1. If an init function is omitted, use a constant function of the appropriate null/zero/false/void type. (For this purpose, a constant void is simply a function which does nothing and returns void; it can be obtained from another constant function by type conversion .)
    2. If a step function is omitted, use an identity function of the clause's iteration variable type; insert dropped argument parameters before the identity function parameter for the non-void iteration variables of preceding clauses. (This will turn the loop variable into a local loop invariant.)
    3. If a pred function is omitted, the corresponding fini function must also be omitted.
    4. If a pred function is omitted, use a constant true function. (This will keep the loop going, as far as this clause is concerned.)
    5. If a fini function is omitted, use a constant null/zero/false/void function of the loop return type.

    Step 4: Fill in missing parameter types.

    1. At this point, every init function parameter list is effectively identical to the common suffix, but some lists may be shorter. For every init function with a short parameter list, pad out the end of the list by dropping arguments .
    2. At this point, every non-init function parameter list is effectively identical to the common parameter sequence, but some lists may be shorter. For every non-init function with a short parameter list, pad out the end of the list by dropping arguments .

    Final observations.

    1. After these steps, all clauses have been adjusted by supplying omitted functions and arguments.
    2. All init functions have a common parameter type list, which the final loop handle will also have.
    3. All fini functions have a common return type, which the final loop handle will also have.
    4. All non-init functions have a common parameter type list, which is the common parameter sequence, of (non-void) iteration variables followed by loop parameters.
    5. Each pair of init and step functions agrees in their return types.
    6. Each non-init function will be able to observe the current values of all iteration variables, by means of the common prefix.

    Loop execution.

    1. When the loop is called, the loop input values are saved in locals, to be passed (as the common suffix) to every clause function. These locals are loop invariant.
    2. Each init function is executed in clause order (passing the common suffix) and the non-void values are saved (as the common prefix) into locals. These locals are loop varying (unless their steps are identity functions, as noted above).
    3. All function executions (except init functions) will be passed the common parameter sequence, consisting of the non-void iteration values (in clause order) and then the loop inputs (in argument order).
    4. The step and pred functions are then executed, in clause order (step before pred), until a pred function returns false.
    5. The non-void result from a step function call is used to update the corresponding loop variable. The updated value is immediately visible to all subsequent function calls.
    6. If a pred function returns false, the corresponding fini function is called, and the resulting value is returned from the loop as a whole.

    Here is pseudocode for the resulting loop handle. In the code, V/v represent the types / values of loop variables; A/a, those of arguments passed to the resulting loop; and R, the result types of finalizers as well as of the resulting loop.

    
     V... init...(A...);
     boolean pred...(V..., A...);
     V... step...(V..., A...);
     R fini...(V..., A...);
     R loop(A... a) {
       V... v... = init...(a...);
       for (;;) {
         for ((v, p, s, f) in (v..., pred..., step..., fini...)) {
           v = s(v..., a...);
           if (!p(v..., a...)) {
             return f(v..., a...);
           }
         }
       }
     }
     
    

    API Note:
    Example:
    
     // iterative implementation of the factorial function as a loop handle
     static int one(int k) { return 1; }
     static int inc(int i, int acc, int k) { return i + 1; }
     static int mult(int i, int acc, int k) { return i * acc; }
     static boolean pred(int i, int acc, int k) { return i < k; }
     static int fin(int i, int acc, int k) { return acc; }
     // assume MH_one, MH_inc, MH_mult, MH_pred, and MH_fin are handles to the above methods
     // null initializer for counter, should initialize to 0
     MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};
     MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};
     MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);
     assertEquals(120, loop.invoke(5));
     
    
    Parameters:
    clauses - an array of arrays (4-tuples) of MethodHandles adhering to the rules described above.
    Returns:
    a method handle embodying the looping behavior as defined by the arguments.
    Throws:
    IllegalArgumentException - in case any of the constraints described above is violated.
    Since:
    9
    See Also:
    whileLoop(MethodHandle, MethodHandle, MethodHandle) , doWhileLoop(MethodHandle, MethodHandle, MethodHandle) , countedLoop(MethodHandle, MethodHandle, MethodHandle) , iteratedLoop(MethodHandle, MethodHandle, MethodHandle)

method:whileLoop(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) [NONE]

  • whileLoop

    public static MethodHandle whileLoop(MethodHandle init,
                                         MethodHandle pred,
                                         MethodHandle body)
    Constructs a while loop from an initializer, a body, and a predicate. This is a convenience wrapper for the generic loop combinator .

    The loop handle's result type is the same as the sole loop variable's, i.e., the result type of init. The parameter type list of init also determines that of the resulting handle. The pred handle must have an additional leading parameter of the same type as init's result, and so must the body . These constraints follow directly from those described for the generic loop combinator .

    Here is pseudocode for the resulting loop handle. In the code, V/v represent the type / value of the sole loop variable as well as the result type of the loop; and A/a, that of the argument passed to the loop.

    
     V init(A);
     boolean pred(V, A);
     V body(V, A);
     V whileLoop(A a) {
       V v = init(a);
       while (pred(v, a)) {
         v = body(v, a);
       }
       return v;
     }
     
    

    API Note:
    Example:
    
     // implement the zip function for lists as a loop handle
     static List<String> initZip(Iterator<String> a, Iterator<String> b) { return new ArrayList<>(); }
     static boolean zipPred(List<String> zip, Iterator<String> a, Iterator<String> b) { return a.hasNext() && b.hasNext(); }
     static List<String> zipStep(List<String> zip, Iterator<String> a, Iterator<String> b) {
       zip.add(a.next());
       zip.add(b.next());
       return zip;
     }
     // assume MH_initZip, MH_zipPred, and MH_zipStep are handles to the above methods
     MethodHandle loop = MethodHandles.whileLoop(MH_initZip, MH_zipPred, MH_zipStep);
     List<String> a = Arrays.asList("a", "b", "c", "d");
     List<String> b = Arrays.asList("e", "f", "g", "h");
     List<String> zipped = Arrays.asList("a", "e", "b", "f", "c", "g", "d", "h");
     assertEquals(zipped, (List<String>) loop.invoke(a.iterator(), b.iterator()));
     
    

    Implementation Requirements:
    The implementation of this method is equivalent to:
    
     MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body) {
         MethodHandle[]
             checkExit = {null, null, pred, identity(init.type().returnType())},
             varBody = {init, body};
         return loop(checkExit, varBody);
     }
     
    
    Parameters:
    init - initializer: it should provide the initial value of the loop variable. This controls the loop's result type. Passing null or a void init function will make the loop's result type void.
    pred - condition for the loop, which may not be null.
    body - body of the loop, which may not be null.
    Returns:
    the value of the loop variable as the loop terminates.
    Throws:
    IllegalArgumentException - if any argument has a type inconsistent with the loop structure
    Since:
    9
    See Also:
    loop(MethodHandle[][])

method:doWhileLoop(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) [NONE]

  • doWhileLoop

    public static MethodHandle doWhileLoop(MethodHandle init,
                                           MethodHandle body,
                                           MethodHandle pred)
    Constructs a do-while loop from an initializer, a body, and a predicate. This is a convenience wrapper for the generic loop combinator .

    The loop handle's result type is the same as the sole loop variable's, i.e., the result type of init. The parameter type list of init also determines that of the resulting handle. The pred handle must have an additional leading parameter of the same type as init's result, and so must the body . These constraints follow directly from those described for the generic loop combinator .

    Here is pseudocode for the resulting loop handle. In the code, V/v represent the type / value of the sole loop variable as well as the result type of the loop; and A/a, that of the argument passed to the loop.

    
     V init(A);
     boolean pred(V, A);
     V body(V, A);
     V doWhileLoop(A a) {
       V v = init(a);
       do {
         v = body(v, a);
       } while (pred(v, a));
       return v;
     }
     
    

    API Note:
    Example:
    
     // int i = 0; while (i < limit) { ++i; } return i; => limit
     static int zero(int limit) { return 0; }
     static int step(int i, int limit) { return i + 1; }
     static boolean pred(int i, int limit) { return i < limit; }
     // assume MH_zero, MH_step, and MH_pred are handles to the above methods
     MethodHandle loop = MethodHandles.doWhileLoop(MH_zero, MH_step, MH_pred);
     assertEquals(23, loop.invoke(23));
     
    

    Implementation Requirements:
    The implementation of this method is equivalent to:
    
     MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) {
         MethodHandle[] clause = { init, body, pred, identity(init.type().returnType()) };
         return loop(clause);
     }
     
    
    Parameters:
    init - initializer: it should provide the initial value of the loop variable. This controls the loop's result type. Passing null or a void init function will make the loop's result type void.
    pred - condition for the loop, which may not be null.
    body - body of the loop, which may not be null.
    Returns:
    the value of the loop variable as the loop terminates.
    Throws:
    IllegalArgumentException - if any argument has a type inconsistent with the loop structure
    Since:
    9
    See Also:
    loop(MethodHandle[][])

method:countedLoop(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) [NONE]

  • countedLoop

    public static MethodHandle countedLoop(MethodHandle iterations,
                                           MethodHandle init,
                                           MethodHandle body)
    Constructs a loop that runs a given number of iterations. The loop counter is an int initialized from the iterations handle evaluation result. The counter is passed to the body function, so that must accept an initial int argument. The result of the loop execution is the final value of the additional local state. This is a convenience wrapper for the generic loop combinator .

    The result type and parameter type list of init determine those of the resulting handle. The iterations handle must accept the same parameter types as init but return an int. The body handle must accept the same parameter types as well, preceded by an int parameter for the counter, and a parameter of the same type as init's result. These constraints follow directly from those described for the generic loop combinator .

    Here is pseudocode for the resulting loop handle. In the code, V/v represent the type / value of the sole loop variable as well as the result type of the loop; and A/a, that of the argument passed to the loop.

    
     int iterations(A);
     V init(A);
     V body(int, V, A);
     V countedLoop(A a) {
       int end = iterations(a);
       V v = init(a);
       for (int i = 0; i < end; ++i) {
         v = body(i, v, a);
       }
       return v;
     }
     
    

    API Note:
    Example:
    
     // String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;
     // => a variation on a well known theme
     static String start(String arg) { return arg; }
     static String step(int counter, String v, String arg) { return "na " + v; }
     // assume MH_start and MH_step are handles to the two methods above
     MethodHandle fit13 = MethodHandles.constant(int.class, 13);
     MethodHandle loop = MethodHandles.countedLoop(fit13, MH_start, MH_step);
     assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!"));
     
    

    Implementation Requirements:
    The implementation of this method is equivalent to:
    
     MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body) {
         return countedLoop(null, iterations, init, body);  // null => constant zero
     }
     
    
    Parameters:
    iterations - a handle to return the number of iterations this loop should run.
    init - initializer for additional loop state. This determines the loop's result type. Passing null or a void init function will make the loop's result type void.
    body - the body of the loop, which must not be null. It must accept an initial int parameter (for the counter), and then any additional loop-local variable plus loop parameters.
    Returns:
    a method handle representing the loop.
    Throws:
    IllegalArgumentException - if any argument has a type inconsistent with the loop structure
    Since:
    9

method:countedLoop(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) [NONE]

  • countedLoop

    public static MethodHandle countedLoop(MethodHandle start,
                                           MethodHandle end,
                                           MethodHandle init,
                                           MethodHandle body)
    Constructs a loop that counts over a range of numbers. The loop counter is an int that will be initialized to the int value returned from the evaluation of the start handle and run to the value returned from end (exclusively) with a step width of 1. The counter value is passed to the body function in each iteration; it has to accept an initial int parameter for that. The result of the loop execution is the final value of the additional local state obtained by running init. This is a convenience wrapper for the generic loop combinator .

    The constraints for the init and body handles are the same as for countedLoop(MethodHandle, MethodHandle, MethodHandle) . Additionally, the start and end handles must return an int and accept the same parameters as init.

    Here is pseudocode for the resulting loop handle. In the code, V/v represent the type / value of the sole loop variable as well as the result type of the loop; and A/a, that of the argument passed to the loop.

    
     int start(A);
     int end(A);
     V init(A);
     V body(int, V, A);
     V countedLoop(A a) {
       int s = start(a);
       int e = end(a);
       V v = init(a);
       for (int i = s; i < e; ++i) {
         v = body(i, v, a);
       }
       return v;
     }
     
    

    Implementation Requirements:
    The implementation of this method is equivalent to:
    
     MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
         MethodHandle returnVar = dropArguments(identity(init.type().returnType()), 0, int.class, int.class);
         // assume MH_increment and MH_lessThan are handles to x+1 and x<y of type int
         MethodHandle[]
             indexVar = {start, MH_increment}, // i = start; i = i+1
             loopLimit = {end, null, MH_lessThan, returnVar }, // i<end
             bodyClause = {init, dropArguments(body, 1, int.class)};  // v = body(i, v);
         return loop(indexVar, loopLimit, bodyClause);
     }
     
    
    Parameters:
    start - a handle to return the start value of the loop counter. If it is null, a constant zero is assumed.
    end - a non-null handle to return the end value of the loop counter (the loop will run to end-1).
    init - initializer for additional loop state. This determines the loop's result type. Passing null or a void init function will make the loop's result type void.
    body - the body of the loop, which must not be null. It must accept an initial int parameter (for the counter), and then any additional loop-local variable plus loop parameters.
    Returns:
    a method handle representing the loop.
    Throws:
    IllegalArgumentException - if any argument has a type inconsistent with the loop structure
    Since:
    9

method:iteratedLoop(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) [NONE]

  • iteratedLoop

    public static MethodHandle iteratedLoop(MethodHandle iterator,
                                            MethodHandle init,
                                            MethodHandle body)
    Constructs a loop that ranges over the elements produced by an Iterator<T>. The iterator will be produced by the evaluation of the iterator handle. If this handle is passed as null the method Iterable.iterator() will be used instead, and will be applied to a leading argument of the loop handle. Each value produced by the iterator is passed to the body, which must accept an initial T parameter. The result of the loop execution is the final value of the additional local state obtained by running init.

    This is a convenience wrapper for the generic loop combinator , and the constraints imposed on the body handle follow directly from those described for the latter.

    Here is pseudocode for the resulting loop handle. In the code, V/v represent the type / value of the loop variable as well as the result type of the loop; T/t, that of the elements of the structure the loop iterates over, and A/a, that of the argument passed to the loop.

    
     Iterator<T> iterator(A);  // defaults to Iterable::iterator
     V init(A);
     V body(T,V,A);
     V iteratedLoop(A a) {
       Iterator<T> it = iterator(a);
       V v = init(a);
       for (T t : it) {
         v = body(t, v, a);
       }
       return v;
     }
     
    

    The type T may be either a primitive or reference. Since type Iterator<T> is erased in the method handle representation to the raw type Iterator, the iteratedLoop combinator adjusts the leading argument type for body to Object as if by the asType conversion method. Therefore, if an iterator of the wrong type appears as the loop is executed, runtime exceptions may occur as the result of dynamic conversions performed by asType.

    API Note:
    Example:
    
     // reverse a list
     static List<String> reverseStep(String e, List<String> r, List<String> l) {
       r.add(0, e);
       return r;
     }
     static List<String> newArrayList(List<String> l) { return new ArrayList<>(); }
     // assume MH_reverseStep, MH_newArrayList are handles to the above methods
     MethodHandle loop = MethodHandles.iteratedLoop(null, MH_newArrayList, MH_reverseStep);
     List<String> list = Arrays.asList("a", "b", "c", "d", "e");
     List<String> reversedList = Arrays.asList("e", "d", "c", "b", "a");
     assertEquals(reversedList, (List<String>) loop.invoke(list));
     
    

    Implementation Requirements:
    The implementation of this method is equivalent to:
    
     MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) {
         // assume MH_next and MH_hasNext are handles to methods of Iterator
         Class<?> itype = iterator.type().returnType();
         Class<?> ttype = body.type().parameterType(0);
         MethodHandle returnVar = dropArguments(identity(init.type().returnType()), 0, itype);
         MethodHandle nextVal = MH_next.asType(MH_next.type().changeReturnType(ttype));
         MethodHandle[]
             iterVar = {iterator, null, MH_hasNext, returnVar}, // it = iterator(); while (it.hasNext)
             bodyClause = {init, filterArgument(body, 0, nextVal)};  // v = body(t, v, a);
         return loop(iterVar, bodyClause);
     }
     
    
    Parameters:
    iterator - a handle to return the iterator to start the loop. Passing null will make the loop call Iterable.iterator() on the first incoming value.
    init - initializer for additional loop state. This determines the loop's result type. Passing null or a void init function will make the loop's result type void.
    body - the body of the loop, which must not be null. It must accept an initial T parameter (for the iterated values), and then any additional loop-local variable plus loop parameters.
    Returns:
    a method handle embodying the iteration loop functionality.
    Throws:
    IllegalArgumentException - if any argument has a type inconsistent with the loop structure
    Since:
    9

method:tryFinally(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) [NONE]

  • tryFinally

    public static MethodHandle tryFinally(MethodHandle target,
                                          MethodHandle cleanup)
    Makes a method handle that adapts a target method handle by wrapping it in a try-finally block. Another method handle, cleanup, represents the functionality of the finally block. Any exception thrown during the execution of the target handle will be passed to the cleanup handle. The exception will be rethrown, unless cleanup handle throws an exception first. The value returned from the cleanup handle's execution will be the result of the execution of the try-finally handle.

    The cleanup handle will be passed one or two additional leading arguments. The first is the exception thrown during the execution of the target handle, or null if no exception was thrown. The second is the result of the execution of the target handle, or, if it throws an exception, a null, zero, or false value of the required type is supplied as a placeholder. The second argument is not present if the target handle has a void return type. (Note that, except for argument type conversions, combinators represent void values in parameter lists by omitting the corresponding paradoxical arguments, not by inserting null or zero values.)

    The target and cleanup handles must have the same corresponding argument and return types, except that the cleanup handle may omit trailing arguments. Also, the cleanup handle must have one or two extra leading parameters:

    • a Throwable, which will carry the exception thrown by the target handle (if any); and
    • a parameter of the same type as the return type of both target and cleanup, which will carry the result from the execution of the target handle. This parameter is not present if the target returns void.

    The pseudocode for the resulting adapter looks as follows. In the code, V represents the result type of the try/finally construct; A/a, the types and values of arguments to the resulting handle consumed by the cleanup; and B/b, those of arguments to the resulting handle discarded by the cleanup.

    
     V target(A..., B...);
     V cleanup(Throwable, V, A...);
     V adapter(A... a, B... b) {
       V result = (zero value for V);
       Throwable throwable = null;
       try {
         result = target(a..., b...);
       } catch (Throwable t) {
         throwable = t;
         throw t;
       } finally {
         result = cleanup(throwable, result, a...);
       }
       return result;
     }
     
    

    Note that the saved arguments (a... in the pseudocode) cannot be modified by execution of the target, and so are passed unchanged from the caller to the cleanup, if it is invoked.

    The target and cleanup must return the same type, even if the cleanup always throws. To create such a throwing cleanup, compose the cleanup logic with throwException, in order to create a method handle of the correct return type.

    Note that tryFinally never converts exceptions into normal returns. In rare cases where exceptions must be converted in that way, first wrap the target with catchException(MethodHandle, Class, MethodHandle) to capture an outgoing exception, and then wrap with tryFinally.

    Parameters:
    target - the handle whose execution is to be wrapped in a try block.
    cleanup - the handle that is invoked in the finally block.
    Returns:
    a method handle embodying the try-finally block composed of the two arguments.
    Throws:
    NullPointerException - if any argument is null
    IllegalArgumentException - if cleanup does not accept the required leading arguments, or if the method handle types do not match in their return types and their corresponding trailing parameters
    Since:
    9
    See Also:
    catchException(MethodHandle, Class, MethodHandle)

method:foldArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle) [NONE]

  • foldArguments

    public static MethodHandle foldArguments(MethodHandle target,
                                             int pos,
                                             MethodHandle combiner)
    Adapts a target method handle by pre-processing some of its arguments, starting at a given position, and then calling the target with the result of the pre-processing, inserted into the original sequence of arguments just before the folded arguments.

    This method is closely related to foldArguments(MethodHandle, MethodHandle) , but allows to control the position in the parameter list at which folding takes place. The argument controlling this, pos, is a zero-based index. The aforementioned method foldArguments(MethodHandle, MethodHandle) assumes position 0.

    API Note:
    Example:
    
        import static java.lang.invoke.MethodHandles.*;
        import static java.lang.invoke.MethodType.*;
        ...
        MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
        "println", methodType(void.class, String.class))
        .bindTo(System.out);
        MethodHandle cat = lookup().findVirtual(String.class,
        "concat", methodType(String.class, String.class));
        assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
        MethodHandle catTrace = foldArguments(cat, 1, trace);
        // also prints "jum":
        assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
     
    

    Here is pseudocode for the resulting adapter. In the code, T represents the result type of the target and resulting adapter. V/v represent the type and value of the parameter and argument of target that precedes the folding position; V also is the result type of the combiner. A/a denote the types and values of the N parameters and arguments at the folding position. Z/z and B/b represent the types and values of the target parameters and arguments that precede and follow the folded parameters and arguments starting at pos, respectively.

    
     // there are N arguments in A...
     T target(Z..., V, A[N]..., B...);
     V combiner(A...);
     T adapter(Z... z, A... a, B... b) {
       V v = combiner(a...);
       return target(z..., v, a..., b...);
     }
     // and if the combiner has a void return:
     T target2(Z..., A[N]..., B...);
     void combiner2(A...);
     T adapter2(Z... z, A... a, B... b) {
       combiner2(a...);
       return target2(z..., a..., b...);
     }
     
    

    Note: The resulting adapter is never a variable-arity method handle , even if the original target method handle was.

    Parameters:
    target - the method handle to invoke after arguments are combined
    pos - the position at which to start folding and at which to insert the folding result; if this is 0 , the effect is the same as for foldArguments(MethodHandle, MethodHandle) .
    combiner - method handle to call initially on the incoming arguments
    Returns:
    method handle which incorporates the specified argument folding logic
    Throws:
    NullPointerException - if either argument is null
    IllegalArgumentException - if combiner's return type is non-void and not the same as the argument type at position pos of the target signature, or if the N argument types at position pos of the target signature (skipping one matching the combiner's return type) are not identical with the argument types of combiner
    Since:
    9
    See Also:
    foldArguments(MethodHandle, MethodHandle)