Class MethodHandles
- 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.
IllegalArgumentException if the created method handle's typewould havetoo many parameters.- Since:
- 1.7
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classAlookup object is a factory for creating method handles,when the creation requires access checking.Method Summary
Modifier and TypeMethodDescriptionstaticMethodHandlearrayConstructor(Class<?> arrayClass) Produces a method handle constructing arrays of a desired type,as if by theanewarraybytecode.staticMethodHandlearrayElementGetter(Class<?> arrayClass) Produces a method handle giving read access to elements of an array,as if by theaaloadbytecode.staticMethodHandlearrayElementSetter(Class<?> arrayClass) Produces a method handle giving write access to elements of an array,as if by theastorebytecode.staticVarHandlearrayElementVarHandle(Class<?> arrayClass) Produces a VarHandle giving access to elements of an array of typearrayClass.staticMethodHandlearrayLength(Class<?> arrayClass) Produces a method handle returning the length of an array,as if by thearraylengthbytecode.staticVarHandlebyteArrayViewVarHandle(Class<?> viewArrayClass,ByteOrder byteOrder) Produces a VarHandle giving access to elements of abyte[]arrayviewed as if it were a different primitive array type, such asint[]orlong[].staticVarHandlebyteBufferViewVarHandle(Class<?> viewArrayClass,ByteOrder byteOrder) Produces a VarHandle giving access to elements of aByteBufferviewed as if it were an array of elements of a different primitivecomponent type to that ofbyte, such asint[]orlong[].staticMethodHandlecatchException(MethodHandle target,Class<? extendsThrowable> exType,MethodHandle handler) Makes a method handle which adapts a target method handle,by running it inside an exception handler.static <T> TclassData(MethodHandles.Lookup caller,String name,Class<T> type) Returns theclass data associated with the lookup classof the givencallerlookup object, ornull.static <T> TclassDataAt(MethodHandles.Lookup caller,String name,Class<T> type, int index) Returns the element at the specified index in theclass data,if the class data associated with the lookup classof the givencallerlookup object is aList.staticMethodHandlecollectArguments(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).staticVarHandlecollectCoordinates(VarHandle target, int pos,MethodHandle filter) Adapts a target var handle by pre-processinga sub-sequence of its coordinate values with a filter (a method handle).staticMethodHandleProduces a method handle of the requested return type which returns the givenconstant value every time it is invoked.staticMethodHandlecountedLoop(MethodHandle iterations,MethodHandle init,MethodHandle body) Constructs a loop that runs a given number of iterations.staticMethodHandlecountedLoop(MethodHandle start,MethodHandle end,MethodHandle init,MethodHandle body) Constructs a loop that counts over a range of numbers.staticMethodHandledoWhileLoop(MethodHandle init,MethodHandle body,MethodHandle pred) Constructs ado-whileloop from an initializer, a body, and a predicate.staticMethodHandledropArguments(MethodHandle target, int pos,Class<?>... valueTypes) Produces a method handle which will discard some dummy arguments before calling some other specifiedtarget method handle.staticMethodHandledropArguments(MethodHandle target, int pos,List<Class<?>> valueTypes) Produces a method handle which will discard some dummy arguments before calling some other specifiedtarget method handle.staticMethodHandledropArgumentsToMatch(MethodHandle target, int skip,List<Class<?>> newTypes, int pos) Adapts a target method handle to match the given parameter type list.staticVarHandledropCoordinates(VarHandle target, int pos,Class<?>... valueTypes) Returns a var handle which will discard some dummy coordinates before delegating to thetarget var handle.staticMethodHandledropReturn(MethodHandle target) Drop the return value of the target handle (if any).staticMethodHandleempty(MethodType type) Produces a method handle of the requested type which ignores any arguments, does nothing,and returns a suitable default depending on the return type.staticMethodHandleexactInvoker(MethodType type) Produces a specialinvoker method handle which can be used toinvoke any method handle of the given type, as if byinvokeExact.staticMethodHandleexplicitCastArguments(MethodHandle target,MethodType newType) Produces a method handle which adapts the type of thegiven method handle to a new type by pairwise argument and return type conversion.staticMethodHandlefilterArguments(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.staticVarHandlefilterCoordinates(VarHandle target, int pos,MethodHandle... filters) Adapts a target var handle by pre-processing incoming coordinate values using unary filter functions.staticMethodHandlefilterReturnValue(MethodHandle target,MethodHandle filter) Adapts a target method handle by post-processing its return value (if any) with a filter (another method handle).staticVarHandlefilterValue(VarHandle target,MethodHandle filterToTarget,MethodHandle filterFromTarget) Adapts a target var handle by pre-processing incoming and outgoing values using a pair of filter functions.staticMethodHandlefoldArguments(MethodHandle target, int pos,MethodHandle combiner) Adapts a target method handle by pre-processing some of its arguments, starting at a given position, and thencalling the target with the result of the pre-processing, inserted into the original sequence of arguments justbefore the folded arguments.staticMethodHandlefoldArguments(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.staticMethodHandleguardWithTest(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.staticMethodHandleProduces a method handle which returns its sole argument when invoked.staticMethodHandleinsertArguments(MethodHandle target, int pos,Object... values) Provides a target method handle with one or morebound argumentsin advance of the method handle's invocation.staticVarHandleinsertCoordinates(VarHandle target, int pos,Object... values) Provides a target var handle with one or morebound coordinatesin advance of the var handle's invocation.staticMethodHandleinvoker(MethodType type) Produces a specialinvoker method handle which can be used toinvoke any method handle compatible with the given type, as if byinvoke.staticMethodHandleiteratedLoop(MethodHandle iterator,MethodHandle init,MethodHandle body) Constructs a loop that ranges over the values produced by anIterator<T>.staticMethodHandles.Lookuplookup()Returns alookup objectwithfull capabilities to emulate all supported bytecode behaviors of the caller.staticMethodHandleloop(MethodHandle[]... clauses) Constructs a method handle representing a loop with several loop variables that are updated and checked upon eachiteration.staticMethodHandlepermuteArguments(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.staticVarHandlepermuteCoordinates(VarHandle target,List<Class<?>> newCoordinates, int... reorder) Provides a var handle which adapts the coordinate values of the target var handle, by re-arranging themso that the new coordinates match the provided ones.staticMethodHandles.LookupprivateLookupIn(Class<?> targetClass,MethodHandles.Lookup caller) Returns alookupobject on a target class to emulate all supportedbytecode behaviors, includingprivate access.staticMethodHandles.LookupReturns alookup objectwhich is trusted minimally.static <T extendsMember>
TreflectAs(Class<T> expected,MethodHandle target) Performs an unchecked "crack" of adirect method handle.staticMethodHandlespreadInvoker(MethodType type, int leadingArgCount) Produces a method handle which will invoke any method handle of the giventype, with a given number of trailing arguments replaced by a single trailingObject[]array.staticMethodHandletableSwitch(MethodHandle fallback,MethodHandle... targets) Creates a table switch method handle, which can be used to switch over a set of targetmethod handles, based on a given target index, called selector.staticMethodHandlethrowException(Class<?> returnType,Class<? extendsThrowable> exType) Produces a method handle which will throw exceptions of the givenexType.staticMethodHandletryFinally(MethodHandle target,MethodHandle cleanup) Makes a method handle that adapts atargetmethod handle by wrapping it in atry-finallyblock.staticMethodHandlevarHandleExactInvoker(VarHandle.AccessMode accessMode,MethodType type) Produces a specialinvoker method handle which can be used toinvoke a signature-polymorphic access mode method on any VarHandle whoseassociated access mode type is compatible with the given type.staticMethodHandlevarHandleInvoker(VarHandle.AccessMode accessMode,MethodType type) Produces a specialinvoker method handle which can be used toinvoke a signature-polymorphic access mode method on any VarHandle whoseassociated access mode type is compatible with the given type.staticMethodHandlewhileLoop(MethodHandle init,MethodHandle pred,MethodHandle body) Constructs awhileloop from an initializer, a body, and a predicate.staticMethodHandleProduces a constant method handle of the requested return type whichreturns the default value for that type every time it is invoked.
Method Details
lookup
Returns alookup objectwithfull capabilities to emulate all supported bytecode behaviors of the caller.These capabilities includefull privilege access to the caller.Factory methods on the lookup object can createdirect method handlesfor any member that the caller has access to via bytecodes,including protected and private fields and methods.This lookup object is created by the original lookup classand has theORIGINALbit set.This lookup object is acapability 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 differentvalues to different callers.In cases where
MethodHandles.lookupis called from a context wherethere is no caller frame on the stack (e.g. when called directlyfrom a JNI attached thread),IllegalCallerExceptionis thrown.To obtain alookup objectin such a context, use an auxiliary class that willimplicitly be identified as the caller, or usepublicLookup()to obtain a low-privileged lookup instead.- Returns:
- a lookup object for the caller of this method, withoriginal andfull privilege access.
- Throws:
IllegalCallerException- if there is no caller frame on the stack.
publicLookup
Returns alookup objectwhich is trusted minimally.The lookup has theUNCONDITIONALmode.It can only be used to create method handles to public members ofpublic classes in packages that are exported unconditionally.As a matter of pure convention, thelookup classof this lookup object will be
Object.- API Note:
- The use of Object is conventional, and because the lookup modes arelimited, there is no special access provided to the internals of Object, its packageor its module. This public lookup object or other lookup object with
UNCONDITIONALmode assumes readability. Consequently, the lookup classis not used to determine the lookup context.Discussion:The lookup class can be changed to any other class
Cusing an expression of the formpublicLookup().in(C.class).Also, it cannot accesscaller sensitive methods. - Returns:
- a lookup object which is trusted minimally
privateLookupIn
public static MethodHandles.Lookup privateLookupIn(Class<?> targetClass,MethodHandles.Lookup caller) throwsIllegalAccessException Returns alookupobject on a target class to emulate all supportedbytecode behaviors, includingprivate access.The returned lookup object can provide access to classes in modules and packages,and members of those classes, outside the normal rules of Java access control,instead conforming to the more permissive rules for modulardeep reflection.A caller, specified as a
Lookupobject, in moduleM1isallowed to do deep reflection on moduleM2and package of the target classif and only if all of the following conditions aretrue:- The caller lookup object must havefull privilege access. Specifically:
- The caller lookup object must have the
MODULElookup mode. (This is because otherwise there would be no way to ensure the original lookup creator was a member of any particular module, and so any subsequent checks for readability and qualified exports would become ineffective.) - The caller lookup object must have
PRIVATEaccess. (This is because an application intending to share intra-module access usingMODULEalone will inadvertently also share deep reflection to its own module.)
- The caller lookup object must have the
- The target class must be a proper class, not a primitive or array class.(Thus,
M2is well-defined.) - If the caller module
M1differs fromthe target moduleM2then both of the following must be true:
If any of the above checks is violated, this method fails with anexception.
Otherwise, if
M1andM2are the same module, this methodreturns aLookupontargetClasswithfull privilege accesswithnullprevious lookup class.Otherwise,
M1andM2are two different modules. This methodreturns aLookupontargetClassthat recordsthe lookup class of the caller as the new previous lookup class withPRIVATEaccess but noMODULEaccess.The resulting
Lookupobject has noORIGINALaccess.- API Note:
- The
Lookupobject returned by this method is allowed todefine classes in the runtime packageoftargetClass. Extreme caution should be taken when opening a packageto another module as such defined classes have the same full privilegeaccess as other members intargetClass's module. - Parameters:
targetClass- the target classcaller- the caller lookup object- Returns:
- a lookup object for the target class, with private access
- Throws:
IllegalArgumentException- iftargetClassis a primitive type or void or array classNullPointerException- iftargetClassorcallerisnullIllegalAccessException- if any of the other access checks specified above fails- Since:
- 9
- See Also:
- The caller lookup object must havefull privilege access. Specifically:
classData
public static <T> T classData(MethodHandles.Lookup caller,String name,Class<T> type) throwsIllegalAccessException Returns theclass data associated with the lookup classof the givencallerlookup object, ornull.A hidden class with class data can be created by calling
Lookup::defineHiddenClassWithClassData.This method will cause the static class initializer of the lookupclass of the givencallerlookup object be executed ifit has not been initialized.A hidden class created by
Lookup::defineHiddenClassand non-hidden classes have no class data.nullis returned if this method is called on the lookup objecton these classes.Thelookup modes for this lookupmust haveoriginal accessin order to retrieve the class data.
- API Note:
- This method can be called as a bootstrap method for a dynamically computedconstant. A framework can create a hidden class with class data, forexample that can be
ClassorMethodHandleobject.The class data is accessible only to the lookup objectcreated by the original caller but inaccessible to other membersin the same nest. If a framework passes security sensitive objectsto a hidden class via class data, it is recommended to load the valueof class data as a dynamically computed constant instead of storingthe class data in private static field(s) which are accessible toother nestmates. - Type Parameters:
T- the type to cast the class data object to- Parameters:
caller- the lookup context describing the class performing theoperation (normally stacked by the JVM)name- must beConstantDescs.DEFAULT_NAME("_")type- the type of the class data- Returns:
- the value of the class data if present in the lookup class;otherwise
null - Throws:
IllegalArgumentException- if name is not"_"IllegalAccessException- if the lookup context does not haveoriginal accessClassCastException- if the class data cannot be converted tothe giventypeNullPointerException- ifcallerortypeargumentisnull- SeeJava Virtual Machine Specification:
- 5.5 Initialization
- Since:
- 16
- See Also:
classDataAt
public static <T> T classDataAt(MethodHandles.Lookup caller,String name,Class<T> type, int index) throwsIllegalAccessException Returns the element at the specified index in theclass data,if the class data associated with the lookup classof the givencallerlookup object is aList.If the class data is not present in this lookup class, this methodreturnsnull.A hidden class with class data can be created by calling
Lookup::defineHiddenClassWithClassData.This method will cause the static class initializer of the lookupclass of the givencallerlookup object be executed ifit has not been initialized.A hidden class created by
Lookup::defineHiddenClassand non-hidden classes have no class data.nullis returned if this method is called on the lookup objecton these classes.Thelookup modes for this lookupmust haveoriginal accessin order to retrieve the class data.
- API Note:
- This method can be called as a bootstrap method for a dynamically computedconstant. A framework can create a hidden class with class data, forexample that can be
List.of(o1, o2, o3....)containing more thanone object and use this method to load one element at a specific index.The class data is accessible only to the lookup objectcreated by the original caller but inaccessible to other membersin the same nest. If a framework passes security sensitive objectsto a hidden class via class data, it is recommended to load the valueof class data as a dynamically computed constant instead of storingthe class data in private static field(s) which are accessible to othernestmates. - Type Parameters:
T- the type to cast the result object to- Parameters:
caller- the lookup context describing the class performing theoperation (normally stacked by the JVM)name- must beConstantDescs.DEFAULT_NAME("_")type- the type of the element at the given index in the class dataindex- index of the element in the class data- Returns:
- the element at the given index in the class dataif the class data is present; otherwise
null - Throws:
IllegalArgumentException- if name is not"_"IllegalAccessException- if the lookup context does not haveoriginal accessClassCastException- if the class data cannot be converted toListor the element at the specified index cannot be converted to the given typeIndexOutOfBoundsException- if the index is out of rangeNullPointerException- ifcallerortypeargument isnull; or if unboxing operation fails becausethe element at the given index isnull- Since:
- 16
- See Also:
reflectAs
Performs an unchecked "crack" of adirect method handle.The result is as if the user had obtained a lookup object capable enoughto crack the target method handle, calledLookup.revealDirecton the target to obtain its symbolic reference, and then calledMethodHandleInfo.reflectAsto resolve the symbolic reference to a member.- Type Parameters:
T- the desired type of the result, eitherMemberor a subtype- Parameters:
expected- a class object representing the desired result typeTtarget- a direct method handle to crack into symbolic reference components- Returns:
- a reference to the method, constructor, or field object
- Throws:
NullPointerException- if either argument isnullIllegalArgumentException- if the target is not a direct method handleClassCastException- if the member is not of the expected type- Since:
- 1.8
arrayConstructor
Produces a method handle constructing arrays of a desired type,as if by theanewarraybytecode.The return type of the method handle will be the array type.The type of its sole argument will beint, which specifies the size of the array.If the returned method handle is invoked with a negativearray size, a
NegativeArraySizeExceptionwill be thrown.- Parameters:
arrayClass- an array type- Returns:
- a method handle which can create arrays of the given type
- Throws:
NullPointerException- if the argument isnullIllegalArgumentException- ifarrayClassis not an array type- SeeJava Virtual Machine Specification:
- 6.5
anewarrayInstruction - Since:
- 9
- See Also:
arrayLength
Produces a method handle returning the length of an array,as if by thearraylengthbytecode.The type of the method handle will haveintas return type,and its sole argument will be the array type.If the returned method handle is invoked with a
nullarray reference, aNullPointerExceptionwill be thrown.- Parameters:
arrayClass- an array type- Returns:
- a method handle which can retrieve the length of an array of the given array type
- Throws:
NullPointerException- if the argument isnullIllegalArgumentException- if arrayClass is not an array type- SeeJava Virtual Machine Specification:
- 6.5
arraylengthInstruction - Since:
- 9
arrayElementGetter
Produces a method handle giving read access to elements of an array,as if by theaaloadbytecode.The type of the method handle will have a return type of the array'selement type. Its first argument will be the array type,and the second will beint.When the returned method handle is invoked,the array reference and array index are checked.A
NullPointerExceptionwill be thrown if the array referenceisnulland anArrayIndexOutOfBoundsExceptionwill bethrown if the index is negative or if it is greater than or equal tothe length of the array.- Parameters:
arrayClass- an array type- Returns:
- a method handle which can load values from the given array type
- Throws:
NullPointerException- if the argument is nullIllegalArgumentException- if arrayClass is not an array type- SeeJava Virtual Machine Specification:
- 6.5
aaloadInstruction
arrayElementSetter
Produces a method handle giving write access to elements of an array,as if by theastorebytecode.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.When the returned method handle is invoked,the array reference and array index are checked.A
NullPointerExceptionwill be thrown if the array referenceisnulland anArrayIndexOutOfBoundsExceptionwill bethrown if the index is negative or if it is greater than or equal tothe length of the array.- 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 nullIllegalArgumentException- if arrayClass is not an array type- SeeJava Virtual Machine Specification:
- 6.5
aastoreInstruction
arrayElementVarHandle
Produces a VarHandle giving access to elements of an array of typearrayClass. The VarHandle's variable type is the component typeofarrayClassand the list of coordinate types is(arrayClass, int), where theintcoordinate typecorresponds to an argument that is an index into an array.Certain access modes of the returned VarHandle are unsupported underthe following conditions:
- if the component type is anything other than
byte,short,char,int,long,float, ordoublethen numeric atomic update access modes are unsupported. - if the component type is anything other than
boolean,byte,short,char,intorlongthen bitwise atomic update access modes are unsupported.
If the component type is
floatordoublethen numericand atomic update access modes compare values using their bitwiserepresentation (seeFloat.floatToRawIntBits(float)andDouble.doubleToRawLongBits(double), respectively).When the returned
VarHandleis invoked,the array reference and array index are checked.ANullPointerExceptionwill be thrown if the array referenceisnulland anArrayIndexOutOfBoundsExceptionwill bethrown if the index is negative or if it is greater than or equal tothe length of the array.- API Note:
- Bitwise comparison of
floatvalues ordoublevalues,as performed by the numeric and atomic update access modes, differfrom the primitive==operator and theFloat.equals(Object)andDouble.equals(Object)methods, specifically with respect tocomparing NaN values or comparing-0.0with+0.0.Care should be taken when performing a compare and set or a compareand exchange operation with such values since the operation mayunexpectedly fail.There are many possible NaN values that are considered to beNaNin Java, although no IEEE 754 floating-point operationprovided by Java can distinguish between them. Operation failure canoccur if the expected or witness value is a NaN value and it istransformed (perhaps in a platform specific manner) into another NaNvalue, and thus has a different bitwise representation (seeFloat.intBitsToFloat(int)orDouble.longBitsToDouble(long)for moredetails).The values-0.0and+0.0have different bitwiserepresentations but are considered equal when using the primitive==operator. Operation failure can occur if, for example, anumeric algorithm computes an expected value to be say-0.0and previously computed the witness value to be say+0.0. - Parameters:
arrayClass- the class of an array, of typeT[]- Returns:
- a VarHandle giving access to elements of an array
- Throws:
NullPointerException- if the arrayClass is nullIllegalArgumentException- if arrayClass is not an array type- Since:
- 9
- if the component type is anything other than
byteArrayViewVarHandle
public static VarHandle byteArrayViewVarHandle(Class<?> viewArrayClass,ByteOrder byteOrder) throwsIllegalArgumentException Produces a VarHandle giving access to elements of abyte[]arrayviewed as if it were a different primitive array type, such asint[]orlong[].The VarHandle's variable type is the component type ofviewArrayClassand the list of coordinate types is(byte[], int), where theintcoordinate typecorresponds to an argument that is an index into abyte[]array.The returned VarHandle accesses bytes at an index in abyte[]array, composing bytes to or from a value of the component type ofviewArrayClassaccording to the given endianness.The supported component types (variables types) are
short,char,int,long,floatanddouble.Access of bytes at a given index will result in an
ArrayIndexOutOfBoundsExceptionif the index is less than0or greater than thebyte[]array length minus the size (in bytes)ofT.Only plainget andsetaccess modes are supported by the returned var handle. For all other access modes, an
UnsupportedOperationExceptionwill be thrown.- API Note:
- if access modes other than plain access are required, clients shouldconsider using off-heap memory throughdirect byte buffers oroff-heapmemory segments,or memory segments backed by a
long[],for which stronger alignment guarantees can be made. - Parameters:
viewArrayClass- the view array class, with a component type oftypeTbyteOrder- the endianness of the view array elements, asstored in the underlyingbytearray- Returns:
- a VarHandle giving access to elements of a
byte[]arrayviewed as if elements corresponding to the components type of the viewarray class - Throws:
NullPointerException- if viewArrayClass or byteOrder is nullIllegalArgumentException- if viewArrayClass is not an array typeUnsupportedOperationException- if the component type ofviewArrayClass is not supported as a variable type- Since:
- 9
byteBufferViewVarHandle
public static VarHandle byteBufferViewVarHandle(Class<?> viewArrayClass,ByteOrder byteOrder) throwsIllegalArgumentException Produces a VarHandle giving access to elements of aByteBufferviewed as if it were an array of elements of a different primitivecomponent type to that ofbyte, such asint[]orlong[].The VarHandle's variable type is the component type ofviewArrayClassand the list of coordinate types is(ByteBuffer, int), where theintcoordinate typecorresponds to an argument that is an index into abyte[]array.The returned VarHandle accesses bytes at an index in aByteBuffer, composing bytes to or from a value of the componenttype ofviewArrayClassaccording to the given endianness.The supported component types (variables types) are
short,char,int,long,floatanddouble.Access will result in a
ReadOnlyBufferExceptionfor anythingother than the read access modes if theByteBufferis read-only.Access of bytes at a given index will result in an
IndexOutOfBoundsExceptionif the index is less than0or greater than theByteBufferlimit minus the size (in bytes) ofT.For heap byte buffers, access is always unaligned. As a result, only the plaingetandset access modes are supported by thereturned var handle. For all other access modes, an
IllegalStateExceptionwill be thrown.For direct buffers only, access of bytes at an index may be aligned or misaligned for
T,with respect to the underlying memory address,Asay, associatedwith theByteBufferand index.If access is misaligned then access for anything other than thegetandsetaccess modes will result in anIllegalStateException. In such cases atomic access is onlyguaranteed with respect to the largest power of two that divides the GCDofAand the size (in bytes) ofT.If access is aligned then following access modes are supported and areguaranteed to support atomic access:- read write access modes for all
T. Access modesgetandsetforlonganddoubleare supported but have no atomicity guarantee, as described in Section17.7 ofThe Java Language Specification. - atomic update access modes for
int,long,floatordouble. (Future major platform releases of the JDK may support additional types for certain currently unsupported access modes.) - numeric atomic update access modes for
intandlong. (Future major platform releases of the JDK may support additional numeric types for certain currently unsupported access modes.) - bitwise atomic update access modes for
intandlong. (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 determinedfor a
ByteBuffer,bb(direct or otherwise), anindex,Tand its corresponding boxed type,T_BOX, as follows:int sizeOfT = T_BOX.BYTES; // size in bytes of TByteBuffer bb = ...int misalignedAtIndex = bb.alignmentOffset(index, sizeOfT);boolean isMisaligned = misalignedAtIndex != 0;If the variable type is
floatordoublethen atomicupdate access modes compare values using their bitwise representation(seeFloat.floatToRawIntBits(float)andDouble.doubleToRawLongBits(double), respectively).- Parameters:
viewArrayClass- the view array class, with a component type oftypeTbyteOrder- the endianness of the view array elements, asstored in the underlyingByteBuffer(Note this overrides theendianness of aByteBuffer)- Returns:
- a VarHandle giving access to elements of a
ByteBufferviewed as if elements corresponding to the components type of the viewarray class - Throws:
NullPointerException- if viewArrayClass or byteOrder is nullIllegalArgumentException- if viewArrayClass is not an array typeUnsupportedOperationException- if the component type ofviewArrayClass is not supported as a variable type- Since:
- 9
- read write access modes for all
spreadInvoker
Produces a method handle which will invoke any method handle of the giventype, with a given number of trailing arguments replaced by a single trailingObject[]array. The resulting invoker will be a method handle with the following arguments:- a single
MethodHandletarget - zero or more leading values (counted by
leadingArgCount) - an
Object[]array containing trailing arguments
The invoker will invoke its target like a call to
invokewith the indicatedtype. That is, if the target is exactly of the giventype, it will behave likeinvokeExact; otherwise it behave as ifasTypeis used to convert the target to the requiredtype.The type of the returned invoker will not be the given
type, but rather will have all parameters except the firstleadingArgCountreplaced by a single array of typeObject[], 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
IllegalArgumentExceptioninstead of invoking the target.This method is equivalent to the following code (though it may be more efficient):
This method throws no reflective exceptions.MethodHandle invoker = MethodHandles.invoker(type);int spreadArgCount = type.parameterCount() - leadingArgCount;invoker = invoker.asSpreader(Object[].class, spreadArgCount);return invoker;- Parameters:
type- the desired target typeleadingArgCount- 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- iftypeis nullIllegalArgumentException- ifleadingArgCountis not in the range from 0 totype.parameterCount()inclusive, or if the resulting method handle's type would havetoo many parameters
- a single
exactInvoker
Produces a specialinvoker method handle which can be used toinvoke any method handle of the given type, as if byinvokeExact.The resulting invoker will have a type which isexactly equal to the desired type, except that it will acceptan additional leading argument of typeMethodHandle.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 handlesof unknown types.For example, to emulate an
invokeExactcall to a variable methodhandleM, extract its typeT,look up the invoker methodXforT,and call the invoker method, asX.invoke(T, A...).(It would not work to callX.invokeExact, since the typeTis unknown.)If spreading, collecting, or other argument transformations are required,they can be applied once to the invokerXand reused on manyMmethod handle values, as long as they are compatible with the type ofX.(Note: The invoker method is not available via the Core Reflection API.An attempt to calljava.lang.reflect.Method.invokeon the declared
invokeExactorinvokemethod will raise anUnsupportedOperationException.)This method throws no reflective 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 havetoo many parameters
invoker
Produces a specialinvoker method handle which can be used toinvoke any method handle compatible with the given type, as if byinvoke.The resulting invoker will have a type which isexactly equal to the desired type, except that it will acceptan additional leading argument of typeMethodHandle.Before invoking its target, if the target differs from the expected type,the invoker will apply reference casts asnecessary and box, unbox, or widen primitive values, as if by
asType.Similarly, the return value will be converted as necessary.If the target is avariable arity method handle,the required arity conversion will be made, again as if byasType.This method is equivalent to the following code (though it may be more efficient):
publicLookup().findVirtual(MethodHandle.class, "invoke", type)Discussion:Ageneral method type is one whichmentions only
Objectarguments and return values.An invoker for such a type is capable of calling any method handleof the same arity as the general type.(Note: The invoker method is not available via the Core Reflection API.An attempt to calljava.lang.reflect.Method.invokeon the declared
invokeExactorinvokemethod will raise anUnsupportedOperationException.)This method throws no reflective 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 havetoo many parameters
varHandleExactInvoker
Produces a specialinvoker method handle which can be used toinvoke a signature-polymorphic access mode method on any VarHandle whoseassociated access mode type is compatible with the given type.The resulting invoker will have a type which is exactly equal to thedesired given type, except that it will accept an additional leadingargument of typeVarHandle.- Parameters:
accessMode- the VarHandle access modetype- 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
varHandleInvoker
Produces a specialinvoker method handle which can be used toinvoke a signature-polymorphic access mode method on any VarHandle whoseassociated access mode type is compatible with the given type.The resulting invoker will have a type which is exactly equal to thedesired given type, except that it will accept an additional leadingargument of typeVarHandle.Before invoking its target, if the access mode type differs from thedesired given type, the invoker will apply reference casts as necessaryand box, unbox, or widen primitive values, as if by
asType. Similarly, the return value will beconverted as necessary.This method is equivalent to the following code (though it may be moreefficient):
publicLookup().findVirtual(VarHandle.class, accessMode.name(), type)- Parameters:
accessMode- the VarHandle access modetype- 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
explicitCastArguments
Produces a method handle which adapts the type of thegiven 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 typewhich 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 typesT0,T1, one of the following conversions is appliedif possible, before or instead of any conversions done byasType:- IfT0 andT1 are references, andT1 is an interface type, then the value of typeT0 is passed as aT1 without a cast. (This treatment of interfaces follows the usage of the bytecode verifier.)
- IfT0 is boolean andT1 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.)
- IfT1 is boolean andT0 is another primitive,T0 is converted to byte via Java casting conversion (JLS5.5), and the low order bit of the result is tested, as if by
(x & 1) != 0. - IfT0 andT1 are primitives other than boolean, then a Java casting conversion (JLS5.5) is applied. (Specifically,T0 will convert toT1 by widening and/or narrowing.)
- IfT0 is a reference andT1 a primitive, an unboxing conversion will be applied at runtime, possibly followed by a Java casting conversion (JLS5.5) on the primitive value, possibly followed by a conversion from byte to boolean by testing the low-order bit.
- IfT0 is a reference andT1 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 retypednewType- 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 nullWrongMethodTypeException- if the conversion cannot be made- See Also:
permuteArguments
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
#Ithe number of incoming parameters (the valuenewType.parameterCount(), and call#Othe number of outgoing parameters (the valuetarget.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 everyNless than#O, theN-th outgoing argument will be taken from theI-th incoming argument, whereIisreorder[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 ofnewTypemust 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 bynewType.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 avariable-arity method handle, even if the original target method handle was.
- Parameters:
target- the method handle to invoke after arguments are reorderednewType- the expected type of the new method handlereorder- 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 nullIllegalArgumentException- 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 ofnewType, or if two corresponding parameter types intarget.type()andnewTypeare not identical,
constant
Produces a method handle of the requested return type which returns the givenconstant 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 handlevalue- 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 thetypeargument is nullClassCastException- if the value cannot be converted to the required return typeIllegalArgumentException- if the given type isvoid.class
identity
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 nullIllegalArgumentException- if the given type isvoid.class
zero
Produces a constant method handle of the requested return type whichreturns the default value for that type every time it is invoked.The resulting constant method handle will have no side effects.The returned method handle is equivalent to
empty(methodType(type)).It is also equivalent toexplicitCastArguments(constant(Object.class, null), methodType(type)),sinceexplicitCastArgumentsconvertsnullto default values.- Parameters:
type- the expected return type of the desired method handle- Returns:
- a constant method handle that takes no arguments and returns the default value of the given type (or void, if the type is void)
- Throws:
NullPointerException- if the argument is null- Since:
- 9
- See Also:
empty
Produces a method handle of the requested type which ignores any arguments, does nothing,and returns a suitable default depending on the return type.That is, it returns a zero primitive value, anull, orvoid.The returned method handle is equivalent to
dropArguments(zero(type.returnType()), 0, type.parameterList()).- API Note:
- Given a predicate and target, a useful "if-then" construct can be produced as
guardWithTest(pred, target, empty(target.type()). - Parameters:
type- the type of the desired method handle- Returns:
- a constant method handle of the given type, which returns a default value of the given return type
- Throws:
NullPointerException- if the argument is null- Since:
- 9
- See Also:
insertArguments
Provides a target method handle with one or morebound argumentsin advance of the method handle's invocation.The formal parameters to the target corresponding to the boundarguments are calledbound 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 boundparameters from the original target type, since the new method handlewill 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 objectmust be a wrapper, and will be unboxed to produce the primitive value.
The
posargument selects which parameters are to be bound.It may range between zero andN-L (inclusively),whereN is the arity of the target method handleandL is the length of the values array.Note: The resulting adapter is never avariable-arity method handle, even if the original target method handle was.
- Parameters:
target- the method handle to invoke after the argument is insertedpos- 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 thevaluesarray is nullIllegalArgumentException- ifposis less than0or greater thanN - LwhereNis the arity of the target method handle andLis the length of the values array.ClassCastException- if an argument does not match the corresponding bound parameter type.- See Also:
dropArguments
Produces a method handle which will discard some dummy arguments before calling some other specifiedtarget 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
posargument may range between zero andN, whereN is the arity of the target. Ifposis zero, the dummy arguments will precede the target's real arguments; ifposisN 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 droppedpos- position of first argument to drop (zero for the leftmost)valueTypes- the type(s) of the argument(s) to drop- 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 thevalueTypeslist or any of its elements is nullIllegalArgumentException- if any element ofvalueTypesisvoid.class, or ifposis negative or greater than the arity of the target, or if the new method handle's type would have too many parameters
dropArguments
Produces a method handle which will discard some dummy arguments before calling some other specifiedtarget 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
posargument may range between zero andN, whereN is the arity of the target. Ifposis zero, the dummy arguments will precede the target's real arguments; ifposisN they will come after.- API Note:
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 droppedpos- position of first argument to drop (zero for the leftmost)valueTypes- the type(s) of the argument(s) to drop- 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 thevalueTypesarray or any of its elements is nullIllegalArgumentException- if any element ofvalueTypesisvoid.class, or ifposis negative or greater than the arity of the target, or if the new method handle's type would havetoo many parameters
dropArgumentsToMatch
public static MethodHandle dropArgumentsToMatch(MethodHandle target, int skip,List<Class<?>> newTypes, int pos) Adapts a target method handle to match the given parameter type list. If necessary, adds dummy arguments. Some leading parameters can be skipped before matching begins. The remaining types in thetarget's parameter type list must be a sub-list of thenewTypestype list at the starting positionpos. The resulting handle will have the target handle's parameter type list, with any non-matching parameter types (before or after the matching sub-list) inserted in corresponding positions of the target's original parameters, as if bydropArguments(MethodHandle, int, Class[]).The resulting handle will have the same return type as the target handle.
In more formal terms, assume these two type lists:
- The target handle has the parameter type list
S..., M..., with as many types inSas indicated byskip. TheMtypes are those that are supposed to match part of the given type list,newTypes. - The
newTypeslist contains typesP..., M..., A..., with as many types inPas indicated bypos. TheMtypes are precisely those that theMtypes in the target handle's parameter type list are supposed to match. The types inAare additional types found after the matching sub-list.
dropArgumentsToMatchwill have the parameter type listS..., P..., M..., A..., with thePandAtypes inserted as if bydropArguments(MethodHandle, int, Class[]).- API Note:
- Two method handles whose argument lists are "effectively identical" (i.e., identical in a common prefix) may be mutually converted to a common type by two calls to
dropArgumentsToMatch, as follows:import static java.lang.invoke.MethodHandles.*;import static java.lang.invoke.MethodType.*;......MethodHandle h0 = constant(boolean.class, true);MethodHandle h1 = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class));MethodType bigType = h1.type().insertParameterTypes(1, String.class, int.class);MethodHandle h2 = dropArguments(h1, 0, bigType.parameterList());if (h1.type().parameterCount() < h2.type().parameterCount()) h1 = dropArgumentsToMatch(h1, 0, h2.type().parameterList(), 0); // lengthen h1else h2 = dropArgumentsToMatch(h2, 0, h1.type().parameterList(), 0); // lengthen h2MethodHandle h3 = guardWithTest(h0, h1, h2);assertEquals("xy", h3.invoke("x", "y", 1, "a", "b", "c")); - Parameters:
target- the method handle to adaptskip- number of targets parameters to disregard (they will be unchanged)newTypes- the list of types to matchtarget's parameter type list topos- place innewTypeswhere the non-skipped target parameters must occur- Returns:
- a possibly adapted method handle
- Throws:
NullPointerException- if either argument is nullIllegalArgumentException- if any element ofnewTypesisvoid.class, or ifskipis negative or greater than the arity of the target, or ifposis negative or greater than the newTypes list size, or ifnewTypesdoes not contain thetarget's non-skipped parameter types at positionpos.- Since:
- 9
- The target handle has the parameter type list
dropReturn
Drop the return value of the target handle (if any).The returned method handle will have avoidreturn type.- Parameters:
target- the method handle to adapt- Returns:
- a possibly adapted method handle
- Throws:
NullPointerException- iftargetis null- Since:
- 16
filterArguments
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
filtersarray. The first element of the filter array corresponds to theposargument of the target, and so on in sequence. The filter functions are invoked in left to right order.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
Fapplies to theNth argument of the target, thenFmust be a method handle which takes exactly one argument. The type ofF's sole argument replaces the corresponding argument type of the target in the resulting adapted method handle. The return type ofFmust 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")); // XyMethodHandle f1 = filterArguments(cat, 1, upcase);assertEquals("xY", (String) f1.invokeExact("x", "y")); // xYMethodHandle f2 = filterArguments(cat, 0, upcase, upcase);assertEquals("XY", (String) f2.invokeExact("x", "y")); // XYHere is pseudocode for the resulting adapter. In the code,
Tdenotes the return type of both thetargetand resulting adapter.P/pandB/brepresent the types and values of the parameters and arguments that precede and follow the filter positionpos, respectively.A[i]/a[i]stand for the types and values of the filtered parameters and arguments; they also represent the return types of thefilter[i]handles. The latter accept argumentsv[i]of typeV[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 avariable-arity method handle, even if the original target method handle was.
- Parameters:
target- the method handle to invoke after arguments are filteredpos- the position of the first argument to filterfilters- 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 thefiltersarray is nullIllegalArgumentException- if a non-null element offiltersdoes not match a corresponding argument type of target as described above, or if thepos+filters.lengthis greater thantarget.type().parameterCount(), or if the resulting method handle's type would havetoo many parameters
collectArguments
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 positionpos, and that target argument is supplied by the return value of the filter.In all cases,
posmust be greater than or equal to zero, andposmust 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,
Trepresents the return type of thetargetand resulting adapter.V/vstand for the return type and value of thefilter, which are also found in the signature and arguments of thetarget, respectively, unlessVisvoid.A/aandC/crepresent the parameter types and values preceding and following the collection position,pos, in thetarget's signature. They also turn up in the resulting adapter's signature and arguments, where they surroundB/b, which represent the parameter types and arguments to thefilter(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:If the target method handle consumes no arguments besides than the result (if any) of the filtermh = MethodHandles.dropArguments(mh, 1, coll.type().parameterList()); //step 2mh = MethodHandles.foldArguments(mh, coll); //step 1coll, thencollectArguments(mh, 0, coll)is equivalent tofilterReturnValue(coll, mh). If the filter method handlecollconsumes one argument and produces a non-void result, thencollectArguments(mh, N, coll)is equivalent tofilterArguments(mh, N, coll). Other equivalences are possible but would require argument permutation.Note: The resulting adapter is never avariable-arity method handle, even if the original target method handle was.
- Parameters:
target- the method handle to invoke after filtering the subsequence of argumentspos- the position of the first adapter argument to pass to the filter, and/or the target argument which receives the result of the filterfilter- 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 nullIllegalArgumentException- if the return type offilteris non-void and is not the same as theposargument of the target, or ifposis not between 0 and the target's arity, inclusive, or if the resulting method handle's type would havetoo many parameters- See Also:
filterReturnValue
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")); // xyMethodHandle f0 = filterReturnValue(cat, length);System.out.println((int) f0.invokeExact("x", "y")); // 2Here is pseudocode for the resulting adapter. In the code,
T/trepresent the result type and value of thetarget;V, the result type of thefilter; andA/a, the types and values of the parameters and arguments of thetargetas 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 avariable-arity method handle, even if the original target method handle was.
- Parameters:
target- the method handle to invoke before filtering the return valuefilter- 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 nullIllegalArgumentException- if the argument list offilterdoes not match the return type of target as described above
foldArguments
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 firstNarguments are copied to the combiner, which is then called. (Here,Nis defined as the parameter count of the combiner.) After this, control passes to the target, with any result from the combiner inserted before the originalNincoming 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
Nparameter 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
Nparameter 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
dropArgumentscan 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 usingasCollectorinstead, 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,
Trepresents the result type of thetargetand resulting adapter.V/vrepresent the type and value of the parameter and argument oftargetthat precedes the folding position;Valso is the result type of thecombiner.A/adenote the types and values of theNparameters and arguments at the folding position.B/brepresent the types and values of thetargetparameters 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 avariable-arity method handle, even if the original target method handle was.
- Parameters:
target- the method handle to invoke after arguments are combinedcombiner- 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 nullIllegalArgumentException- ifcombiner's return type is non-void and not the same as the first argument type of the target, or if the initialNargument types of the target (skipping one matching thecombiner's return type) are not identical with the argument types ofcombiner
foldArguments
Adapts a target method handle by pre-processing some of its arguments, starting at a given position, and thencalling the target with the result of the pre-processing, inserted into the original sequence of arguments justbefore the folded arguments.This method is closely related to
foldArguments(MethodHandle, MethodHandle), but allows to control theposition in the parameter list at which folding takes place. The argument controlling this,pos, is azero-based index. The aforementioned methodfoldArguments(MethodHandle, MethodHandle)assumes position0.- 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,
Trepresents the result type of thetargetand resulting adapter.V/vrepresent the type and value of the parameter and argumentoftargetthat precedes the folding position;Valso isthe result type of thecombiner.A/adenote thetypes and values of theNparameters and arguments at the foldingposition.Z/zandB/brepresent the typesand values of thetargetparameters and arguments that precede andfollow the folded parameters and arguments starting atpos,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 avariable-arity method handle, even if the original target method handle was.
- Parameters:
target- the method handle to invoke after arguments are combinedpos- the position at which to start folding and at which to insert the folding result; if this is0, the effect is the same as forfoldArguments(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 nullIllegalArgumentException- if either of the following two conditions holds: (1)combiner's return type is non-voidand not the same as the argument type at positionposof the target signature; (2) theNargument types at positionposof the target signature (skipping one matching thecombiner's return type) are not identical with the argument types ofcombiner.- Since:
- 9
- See Also:
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 correspondingargument and return types, except that the return typeof the test must be boolean, and the test is allowedto have fewer arguments than the other two method handles.Here is pseudocode for the resulting adapter. In the code,
Trepresents the uniform result type of the three involved handles;A/a, the types and values of thetargetparameters and arguments that are consumed by thetest; andB/b, those types and values of thetargetparameters and arguments that are not consumed by thetest.Note that the test arguments (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...);}a...in the pseudocode) cannotbe modified by execution of the test, and so are passed unchangedfrom the caller to the target or fallback as appropriate.- Parameters:
test- method handle used for test, must return booleantarget- method handle to call if test passesfallback- method handle to call if test fails- Returns:
- method handle which incorporates the specified if/then/else logic
- Throws:
NullPointerException- if any argument is nullIllegalArgumentException- iftestdoes not return boolean, or if all three method types do not match (with the return type oftestchanged to match that of the target).
catchException
public static MethodHandle catchException(MethodHandle target,Class<? extendsThrowable> 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 fallbackhandle is called instead on the exception, plus the original arguments.The target and handler must have the same correspondingargument 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 ofexTypeor a supertype.Here is pseudocode for the resulting adapter. In the code,
Trepresents the return type of thetargetandhandler,and correspondingly that of the resulting adapter;A/a,the types and values of arguments to the resulting handle consumed byhandler; andB/b, those of arguments to theresulting handle discarded byhandler.Note that the saved arguments (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...); }}a...in the pseudocode) cannotbe modified by execution of the target, and so are passed unchangedfrom the caller to the handler, if the handler is invoked.The target and handler must return the same type, even if the handleralways throws. (This might happen, for instance, because the handleris simulating a
finallyclause).To create such a throwing handler, compose the handler creation logicwiththrowException,in order to create a method handle of the correct return type.- Parameters:
target- method handle to callexType- the type of exception which the handler will catchhandler- 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 nullIllegalArgumentException- ifhandlerdoes 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:
throwException
Produces a method handle which will throw exceptions of the givenexType.The method handle will accept a single argument ofexType,and immediately throw it as an exception.The method type will nominally specify a return ofreturnType.The return type may be anything convenient: It doesn't matter to themethod handle's behavior, since it will never return normally.- Parameters:
returnType- the return type of the desired method handleexType- the parameter type of the desired method handle- Returns:
- method handle which can throw the given exceptions
- Throws:
NullPointerException- if either argument is null
loop
Constructs a method handle representing a loop with several loop variables that are updated and checked upon eachiteration. Upon termination of the loop due to one of the predicates, a corresponding finalizer is run anddelivers 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 localiteration variable and/or a loopexit. Each iteration of the loop executes each clause in order. A clause can optionally update its iterationvariable; it can also optionally perform a test and conditional loop exit. In order to express this logic interms of method handles, each clause will specify up to four independent actions:
- init: Before the loop executes, the initialization of an iteration variable
vof typeV. - step: When a clause executes, an update step for the iteration variable
v. - pred: When a clause executes, a predicate execution to test for loop exit.
- fini: If a clause causes a loop exit, a finalizer execution to compute the loop's return value.
(V...).The values themselves will be(v...). When we speak of "parameter lists", we will usuallybe referring to types, but in some contexts (describing execution) the lists will be of actual values.Some of these clause parts may be omitted according to certain rules, and useful default behavior is provided inthis case. See below for a detailed description.
Parameters optional everywhere:Each clause function is allowed but not required to accept a parameter for each iteration variable
v.As an exception, the init functions cannot take anyvparameters,because those values are not yet computed when the init functions are executed.Any clause function may neglect to take any trailing subsequence of parameters it is entitled to take.In fact, any clause function may take no arguments at all.Loop parameters:A clause function may take all the iteration variable values it is entitled to, in which caseit may also take more trailing parameters. Such extra values are calledloop parameters,with their types and values notated as
(A...)and(a...).These become the parameters of the resulting loop handle, to be supplied whenever the loop is executed.(Since init functions do not accept iteration variablesv, any parameter to aninit function is automatically a loop parametera.)As with iteration variables, clause functions are allowed but not required to accept loop parameters.These loop parameters act as loop-invariant values visible across the whole loop.Parameters visible everywhere:Each non-init clause function is permitted to observe the entire loop state, because it can be passed the fulllist
(v... a...)of current iteration variable values and incoming loop parameters.The init functions can observe initial pre-loop state, in the form(a...).Most clause functions will not need all of this information, but they will be formally connected to itas if bydropArguments(MethodHandle, int, List).More specifically, we shall use the notation(V*)to express an arbitrary prefix of a fullsequence(V...)(and likewise for(v*),(A*),(a*)).In that notation, the general form of an init function parameter listis(A*), and the general form of a non-init function parameter list is(V*)or(V... A*).Checking clause structure:Given a set of clauses, there is a number of checks and adjustments performed to connect all the parts of theloop. They are spelled out in detail in the steps below. In these steps, every occurrence of the word "must"corresponds to a place where
IllegalArgumentExceptionwill be thrown if the required constraint is notmet by the inputs to the loop combinator.Effectively identical sequences:A parameter list
Ais defined to beeffectively identical to another parameter listBifAandBare identical, or ifAis shorter and is identical with a proper prefix ofB.When speaking of an unordered set of parameter lists, we say they the set is "effectively identical"as a whole if the set contains a longest list, and all members of the set are effectively identical tothat longest list.For example, any set of type sequences of the form(V*)is effectively identical,and the same is true if more sequences of the form(V... A*)are added.Step 0: Determine clause structure.
- The clause array (of type
MethodHandle[][]) must be non-nulland contain at least one element. - The clause array may not contain
nulls or sub-arrays longer than four elements. - Clauses shorter than four elements are treated as if they were padded by
nullelements to lengthfour. Padding takes place by appending elements to the array. - Clauses with all
nulls are disregarded. - Each clause is treated as a four-tuple of functions, called "init", "step", "pred", and "fini".
Step 1A: Determine iteration variable types
(V...).- The iteration variable type for each clause is determined using the clause's init and step return types.
- If both functions are omitted, there is no iteration variable for the corresponding clause (
voidisused as the type to indicate that). If one of them is omitted, the other's return type defines the clause'siteration variable type. If both are given, the common return type (they must be identical) defines the clause'siteration variable type. - Form the list of return types (in clause order), omitting all occurrences of
void. - This list of types is called the "iteration variable types" (
(V...)).
Step 1B: Determine loop parameters
(A...).- Examine and collect init function parameter lists (which are of the form
(A*)). - Examine and collect the suffixes of the step, pred, and fini parameter lists, after removing the iteration variable types.(They must have the form
(V... A*); collect the(A*)parts only.) - Do not collect suffixes from step, pred, and fini parameter lists that do not begin with all the iteration variable types.(These types will be checked in step 2, along with all the clause function types.)
- Omitted clause functions are ignored. (Equivalently, they are deemed to have empty parameter lists.)
- All of the collected parameter lists must be effectively identical.
- The longest parameter list (which is necessarily unique) is called the "external parameter list" (
(A...)). - If there is no such parameter list, the external parameter list is taken to be the empty sequence.
- The combined list consisting of iteration variable types followed by the external parameter types is calledthe "internal parameter list".
Step 1C: Determine loop return type.
- Examine fini function return types, disregarding omitted fini functions.
- If there are no fini functions, the loop return type is
void. - Otherwise, the common return type
Rof the fini functions (their return types must be identical) defines the loop returntype.
Step 1D: Check other types.
- There must be at least one non-omitted pred function.
- Every non-omitted pred function must have a
booleanreturn type.
Step 2: Determine parameter lists.
- The parameter list for the resulting loop handle will be the external parameter list
(A...). - The parameter list for init functions will be adjusted to the external parameter list.(Note that their parameter lists are already effectively identical to this list.)
- The parameter list for every non-omitted, non-init (step, pred, and fini) function must beeffectively identical to the internal parameter list
(V... A...).
Step 3: Fill in omitted functions.
- If an init function is omitted, use adefault value for the clause's iteration variabletype.
- If a step function is omitted, use anidentity function of the clause's iterationvariable type; insert dropped argument parameters before the identity function parameter for the non-
voiditeration variables of preceding clauses. (This will turn the loop variable into a local loop invariant.) - If a pred function is omitted, use a constant
truefunction. (This will keep the loop going, as faras this clause is concerned. Note that in such cases the corresponding fini function is unreachable.) - If a fini function is omitted, use adefault value for theloop return type.
Step 4: Fill in missing parameter types.
- At this point, every init function parameter list is effectively identical to the external parameter list
(A...),but some lists may be shorter. For every init function with a short parameter list, pad out the end of the list. - At this point, every non-init function parameter list is effectively identical to the internal parameterlist
(V... A...), but some lists may be shorter. For every non-init function with a short parameter list,pad out the end of the list. - Argument lists are padded out bydropping unused trailing arguments.
Final observations.
- After these steps, all clauses have been adjusted by supplying omitted functions and arguments.
- All init functions have a common parameter type list
(A...), which the final loop handle will also have. - All fini functions have a common return type
R, which the final loop handle will also have. - All non-init functions have a common parameter type list
(V... A...), of(non-void) iteration variablesVfollowed by loop parameters. - Each pair of init and step functions agrees in their return type
V. - Each non-init function will be able to observe the current values
(v...)of all iteration variables. - Every function will be able to observe the incoming values
(a...)of all loop parameters.
Example. As a consequence of step 1A above, the
loopcombinator has the following property:- Given
NclausesCn = {null, Sn, Pn}withn = 1..N. - Suppose predicate handles
Pnare eithernullor have no parameters.(Only onePnhas to be non-null.) - Suppose step handles
Snhave signatures(B1..BX)Rn, for some constantX>=N. - Suppose
Qis the count of non-void typesRn, and(V1...VQ)is the sequence of those types. - It must be that
Vn == Bnforn = 1..min(X,Q). - The parameter types
Vnwill be interpreted as loop-local state elements(V...). - Any remaining types
BQ+1..BX(ifQ<X) will determinethe resulting loop handle's parameter types(A...).
(A...)were derived from the step functions,which is natural if most of the loop computation happens in the steps. For some loops,the burden of computation might be heaviest in the pred functions, and so the pred functionsmight need to accept the loop parameter values. For loops with complex exit logic, the finifunctions might need to accept loop parameters, and likewise for loops with complex entry logic,where the init functions will need the extra parameters. For such reasons, the rules fordetermining these parameters are as symmetric as possible, across all clause parts.In general, the loop parameters function as common invariant values across the wholeloop, while the iteration variables function as common variant values, or (if there isno step function) as internal loop invariant temporaries.Loop execution.
- When the loop is called, the loop input values are saved in locals, to be passed toevery clause function. These locals are loop invariant.
- Each init function is executed in clause order (passing the external arguments
(a...))and the non-voidvalues are saved (as the iteration variables(v...)) into locals.These locals will be loop varying (unless their steps behave as identity functions, as noted above). - All function executions (except init functions) will be passed the internal parameter list, consisting ofthe non-
voiditeration values(v...)(in clause order) and then the loop inputs(a...)(in argument order). - The step and pred functions are then executed, in clause order (step before pred), until a pred functionreturns
false. - The non-
voidresult from a step function call is used to update the corresponding value in thesequence(v...)of loop variables.The updated value is immediately visible to all subsequent function calls. - If a pred function returns
false, the corresponding fini function is called, and the resulting value(of typeR) is returned from the loop as a whole. - If all the pred functions always return true, no fini function is ever invoked, and the loop cannot exitexcept by throwing an exception.
Usage tips.
- Although each step function will receive the current values ofall the loop variables,sometimes a step function only needs to observe the current value of its own variable.In that case, the step function may need to explicitlydrop all preceding loop variables.This will require mentioning their types, in an expression like
dropArguments(step, 0, V0.class, ...). - Loop variables are not required to vary; they can be loop invariant. A clause can createa loop invariant by a suitable init function with no step, pred, or fini function. This may beuseful to "wire" an incoming loop argument into the step or pred function of an adjacent loop variable.
- If some of the clause functions are virtual methods on an instance, the instanceitself can be conveniently placed in an initial invariant loop "variable", using an initial clauselike
new MethodHandle[]{identity(ObjType.class)}. In that case, the instance referencewill be the first iteration variable value, and it will be easy to use virtualmethods as clause parts, since all of them will take a leading instance reference matching that value.
Here is pseudocode for the resulting loop handle. As above,
Vandvrepresent the typesand values of loop variables;Aandarepresent arguments passed to the whole loop;andRis the common result type of all finalizers as well as of the resulting loop.Note that the parameter type listsV... 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...); } } }}(V...)and(A...)have been expandedto their full length, even though individual clause functions may neglect to take them all.As noted above, missing parameters are filled in as if bydropArgumentsToMatch(MethodHandle, int, List, int).- API Note:
- Example:The same example, dropping arguments and using combinators:
// iterative implementation of the factorial function as a loop handlestatic 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 0MethodHandle[] 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));A similar example, using a helper object to hold a loop parameter:// simplified implementation of the factorial function as a loop handlestatic int inc(int i) { return i + 1; } // drop acc, kstatic int mult(int i, int acc) { return i * acc; } //drop kstatic boolean cmp(int i, int k) { return i < k; }// assume MH_inc, MH_mult, and MH_cmp are handles to the above methods// null initializer for counter, should initialize to 0MethodHandle MH_one = MethodHandles.constant(int.class, 1);MethodHandle MH_pred = MethodHandles.dropArguments(MH_cmp, 1, int.class); // drop accMethodHandle MH_fin = MethodHandles.dropArguments(MethodHandles.identity(int.class), 0, int.class); // drop iMethodHandle[] 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(720, loop.invoke(6));// instance-based implementation of the factorial function as a loop handlestatic class FacLoop { final int k; FacLoop(int k) { this.k = k; } int inc(int i) { return i + 1; } int mult(int i, int acc) { return i * acc; } boolean pred(int i) { return i < k; } int fin(int i, int acc) { return acc; }}// assume MH_FacLoop is a handle to the constructor// assume MH_inc, MH_mult, MH_pred, and MH_fin are handles to the above methods// null initializer for counter, should initialize to 0MethodHandle MH_one = MethodHandles.constant(int.class, 1);MethodHandle[] instanceClause = new MethodHandle[]{MH_FacLoop};MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};MethodHandle loop = MethodHandles.loop(instanceClause, counterClause, accumulatorClause);assertEquals(5040, loop.invoke(7)); - Parameters:
clauses- an array of arrays (4-tuples) ofMethodHandles 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:
- init: Before the loop executes, the initialization of an iteration variable
whileLoop
Constructs awhileloop from an initializer, a body, and a predicate.This is a convenience wrapper for thegeneric loop combinator.The
predhandle describes the loop condition; andbody, its body. The loop resulting from thismethod will, in each iteration, first evaluate the predicate and then execute its body (if the predicateevaluates totrue).The loop will terminate once the predicate evaluates tofalse(the body will not be executed in this case).The
inithandle describes the initial value of an additional optional loop-local variable.In each iteration, this loop-local variable, if present, will be passed to thebodyand updated with the value returned from its invocation. The result of loop execution will bethe final value of the additional loop-local variable (if present).The following rules hold for these argument handles:
- The
bodyhandle must not benull; its type must be of the form(V A...)V, whereVis non-void, or else(A...)void.(In thevoidcase, we assign the typevoidto the nameV,and we will write(V A...)Vwith the understanding that avoidtypeVis quietly dropped from the parameter list, leaving(A...)V.) - The parameter list
(V A...)of the body is called theinternal parameter list.It will constrain the parameter lists of the other loop parts. - If the iteration variable type
Vis dropped from the internal parameter list, the resulting shorterlist(A...)is called theexternal parameter list. - The body return type
V, if non-void, determines the type of anadditional state variable of the loop.The body must both accept and return a value of this typeV. - If
initis non-null, it must have return typeV.Its parameter list (of someform(A*)) must beeffectively identicalto the external parameter list(A...). - If
initisnull, the loop variable will be initialized to itsdefault value. - The
predhandle must not benull. It must havebooleanas its return type.Its parameter list (either empty or of the form(V A*)) must beeffectively identical to the internal parameter list.
The resulting loop handle's result type and parameter signature are determined as follows:
- The loop handle's result type is the result type
Vof the body. - The loop handle's parameter types are the types
(A...),from the external parameter list.
Here is pseudocode for the resulting loop handle. In the code,
V/vrepresent the type / value ofthe sole loop variable as well as the result type of the loop; andA/a, that of the argumentpassed 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:, The implementation of this method can be expressed as follows:
// implement the zip function for lists as a loop handlestatic 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 methodsMethodHandle 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()));MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body) { MethodHandle fini = (body.type().returnType() == void.class ? null : identity(body.type().returnType())); MethodHandle[] checkExit = { null, null, pred, fini }, varBody = { init, body }; return loop(checkExit, varBody);} - Parameters:
init- optional initializer, providing the initial value of the loop variable. May benull, implying a default initial value. See above for other constraints.pred- condition for the loop, which may not benull. Its result type must beboolean. See above for other constraints.body- body of the loop, which may not benull. It controls the loop parameters and result type. See above for other constraints.- Returns:
- a method handle implementing the
whileloop as described by the arguments. - Throws:
IllegalArgumentException- if the rules for the arguments are violated.NullPointerException- ifpredorbodyarenull.- Since:
- 9
- See Also:
- The
doWhileLoop
Constructs ado-whileloop from an initializer, a body, and a predicate.This is a convenience wrapper for thegeneric loop combinator.The
predhandle describes the loop condition; andbody, its body. The loop resulting from thismethod will, in each iteration, first execute its body and then evaluate the predicate.The loop will terminate once the predicate evaluates tofalseafter an execution of the body.The
inithandle describes the initial value of an additional optional loop-local variable.In each iteration, this loop-local variable, if present, will be passed to thebodyand updated with the value returned from its invocation. The result of loop execution will bethe final value of the additional loop-local variable (if present).The following rules hold for these argument handles:
- The
bodyhandle must not benull; its type must be of the form(V A...)V, whereVis non-void, or else(A...)void.(In thevoidcase, we assign the typevoidto the nameV,and we will write(V A...)Vwith the understanding that avoidtypeVis quietly dropped from the parameter list, leaving(A...)V.) - The parameter list
(V A...)of the body is called theinternal parameter list.It will constrain the parameter lists of the other loop parts. - If the iteration variable type
Vis dropped from the internal parameter list, the resulting shorterlist(A...)is called theexternal parameter list. - The body return type
V, if non-void, determines the type of anadditional state variable of the loop.The body must both accept and return a value of this typeV. - If
initis non-null, it must have return typeV.Its parameter list (of someform(A*)) must beeffectively identicalto the external parameter list(A...). - If
initisnull, the loop variable will be initialized to itsdefault value. - The
predhandle must not benull. It must havebooleanas its return type.Its parameter list (either empty or of the form(V A*)) must beeffectively identical to the internal parameter list.
The resulting loop handle's result type and parameter signature are determined as follows:
- The loop handle's result type is the result type
Vof the body. - The loop handle's parameter types are the types
(A...),from the external parameter list.
Here is pseudocode for the resulting loop handle. In the code,
V/vrepresent the type / value ofthe sole loop variable as well as the result type of the loop; andA/a, that of the argumentpassed 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:, The implementation of this method can be expressed as follows:
// int i = 0; while (i < limit) { ++i; } return i; => limitstatic 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 methodsMethodHandle loop = MethodHandles.doWhileLoop(MH_zero, MH_step, MH_pred);assertEquals(23, loop.invoke(23));MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) { MethodHandle fini = (body.type().returnType() == void.class ? null : identity(body.type().returnType())); MethodHandle[] clause = { init, body, pred, fini }; return loop(clause);} - Parameters:
init- optional initializer, providing the initial value of the loop variable. May benull, implying a default initial value. See above for other constraints.body- body of the loop, which may not benull. It controls the loop parameters and result type. See above for other constraints.pred- condition for the loop, which may not benull. Its result type must beboolean. See above for other constraints.- Returns:
- a method handle implementing the
whileloop as described by the arguments. - Throws:
IllegalArgumentException- if the rules for the arguments are violated.NullPointerException- ifpredorbodyarenull.- Since:
- 9
- See Also:
- The
countedLoop
Constructs a loop that runs a given number of iterations.This is a convenience wrapper for thegeneric loop combinator.The number of iterations is determined by the
iterationshandle evaluation result.The loop counteriis an extra loop iteration variable of typeint.It will be initialized to 0 and incremented by 1 in each iteration.If the
bodyhandle returns a non-voidtypeV, a leading loop iteration variableof that type is also present. This variable is initialized using the optionalinithandle,or to thedefault value of typeVif that handle isnull.In each iteration, the iteration variables are passed to an invocation of the
bodyhandle.A non-voidvalue returned from the body (of typeV) updates the leadingiteration variable.The result of the loop handle execution will be the finalVvalue of that variable(orvoidif there is noVvariable).The following rules hold for the argument handles:
- The
iterationshandle must not benull, and must returnthe typeint, referred to here asIin parameter type lists. - The
bodyhandle must not benull; its type must be of the form(V I A...)V, whereVis non-void, or else(I A...)void.(In thevoidcase, we assign the typevoidto the nameV,and we will write(V I A...)Vwith the understanding that avoidtypeVis quietly dropped from the parameter list, leaving(I A...)V.) - The parameter list
(V I A...)of the body contributes to a listof types called theinternal parameter list.It will constrain the parameter lists of the other loop parts. - As a special case, if the body contributes only
VandItypes,with no additionalAtypes, then the internal parameter list is extended bythe argument typesA...of theiterationshandle. - If the iteration variable types
(V I)are dropped from the internal parameter list, the resulting shorterlist(A...)is called theexternal parameter list. - The body return type
V, if non-void, determines the type of anadditional state variable of the loop.The body must both accept a leading parameter and return a value of this typeV. - If
initis non-null, it must have return typeV.Its parameter list (of someform(A*)) must beeffectively identicalto the external parameter list(A...). - If
initisnull, the loop variable will be initialized to itsdefault value. - The parameter list of
iterations(of some form(A*)) must beeffectively identical to the external parameter list(A...).
The resulting loop handle's result type and parameter signature are determined as follows:
- The loop handle's result type is the result type
Vof the body. - The loop handle's parameter types are the types
(A...),from the external parameter list.
Here is pseudocode for the resulting loop handle. In the code,
V/vrepresent the type / value ofthe second loop variable as well as the result type of the loop; andA.../a...representarguments passed to the loop.int iterations(A...);V init(A...);V body(V, int, A...);V countedLoop(A... a...) { int end = iterations(a...); V v = init(a...); for (int i = 0; i < end; ++i) { v = body(v, i, a...); } return v;}- API Note:
- Example with a fully conformant body method:, Example with the simplest possible body method type,and passing the number of iterations to the loop invocation:
// String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;// => a variation on a well known themestatic String step(String v, int counter, String init) { return "na " + v; }// assume MH_step is a handle to the method aboveMethodHandle fit13 = MethodHandles.constant(int.class, 13);MethodHandle start = MethodHandles.identity(String.class);MethodHandle loop = MethodHandles.countedLoop(fit13, start, MH_step);assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!"));, Example that treats the number of iterations, string to append to, and string to appendas loop parameters:// String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;// => a variation on a well known themestatic String step(String v, int counter ) { return "na " + v; }// assume MH_step is a handle to the method aboveMethodHandle count = MethodHandles.dropArguments(MethodHandles.identity(int.class), 1, String.class);MethodHandle start = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0, int.class);MethodHandle loop = MethodHandles.countedLoop(count, start, MH_step); // (v, i) -> "na " + vassertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke(13, "Lambdaman!"));, Example that illustrates the usage of// String s = "Lambdaman!", t = "na"; for (int i = 0; i < 13; ++i) { s = t + " " + s; } return s;// => a variation on a well known themestatic String step(String v, int counter, int iterations_, String pre, String start_) { return pre + " " + v; }// assume MH_step is a handle to the method aboveMethodHandle count = MethodHandles.identity(int.class);MethodHandle start = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0, int.class, String.class);MethodHandle loop = MethodHandles.countedLoop(count, start, MH_step); // (v, i, _, pre, _) -> pre + " " + vassertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke(13, "na", "Lambdaman!"));dropArgumentsToMatch(MethodHandle, int, List, int)to enforce a loop type:, The implementation of this method can be expressed as follows:// String s = "Lambdaman!", t = "na"; for (int i = 0; i < 13; ++i) { s = t + " " + s; } return s;// => a variation on a well known themestatic String step(String v, int counter, String pre) { return pre + " " + v; }// assume MH_step is a handle to the method aboveMethodType loopType = methodType(String.class, String.class, int.class, String.class);MethodHandle count = MethodHandles.dropArgumentsToMatch(MethodHandles.identity(int.class), 0, loopType.parameterList(), 1);MethodHandle start = MethodHandles.dropArgumentsToMatch(MethodHandles.identity(String.class), 0, loopType.parameterList(), 2);MethodHandle body = MethodHandles.dropArgumentsToMatch(MH_step, 2, loopType.parameterList(), 0);MethodHandle loop = MethodHandles.countedLoop(count, start, body); // (v, i, pre, _, _) -> pre + " " + vassertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("na", 13, "Lambdaman!"));MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body) { return countedLoop(empty(iterations.type()), iterations, init, body);} - Parameters:
iterations- a non-nullhandle to return the number of iterations this loop should run. The handle's result type must beint. See above for other constraints.init- optional initializer, providing the initial value of the loop variable. May benull, implying a default initial value. See above for other constraints.body- body of the loop, which may not benull. It controls the loop parameters and result type in the standard case (see above for details). It must accept its own return type (if non-void) plus anintparameter (for the counter), and may accept any number of additional types. See above for other constraints.- Returns:
- a method handle representing the loop.
- Throws:
NullPointerException- if either of theiterationsorbodyhandles isnull.IllegalArgumentException- if any argument violates the rules formulated above.- Since:
- 9
- See Also:
- The
countedLoop
public static MethodHandle countedLoop(MethodHandle start,MethodHandle end,MethodHandle init,MethodHandle body) Constructs a loop that counts over a range of numbers.This is a convenience wrapper for thegeneric loop combinator.The loop counter
iis a loop iteration variable of typeint.Thestartandendhandles determine the start (inclusive) and end (exclusive)values of the loop counter.The loop counter will be initialized to theintvalue returned from the evaluation of thestarthandle and run to the value returned fromend(exclusively) with a step width of 1.If the
bodyhandle returns a non-voidtypeV, a leading loop iteration variableof that type is also present. This variable is initialized using the optionalinithandle,or to thedefault value of typeVif that handle isnull.In each iteration, the iteration variables are passed to an invocation of the
bodyhandle.A non-voidvalue returned from the body (of typeV) updates the leadingiteration variable.The result of the loop handle execution will be the finalVvalue of that variable(orvoidif there is noVvariable).The following rules hold for the argument handles:
- The
startandendhandles must not benull, and must both returnthe common typeint, referred to here asIin parameter type lists. - The
bodyhandle must not benull; its type must be of the form(V I A...)V, whereVis non-void, or else(I A...)void.(In thevoidcase, we assign the typevoidto the nameV,and we will write(V I A...)Vwith the understanding that avoidtypeVis quietly dropped from the parameter list, leaving(I A...)V.) - The parameter list
(V I A...)of the body contributes to a listof types called theinternal parameter list.It will constrain the parameter lists of the other loop parts. - As a special case, if the body contributes only
VandItypes,with no additionalAtypes, then the internal parameter list is extended bythe argument typesA...of theendhandle. - If the iteration variable types
(V I)are dropped from the internal parameter list, the resulting shorterlist(A...)is called theexternal parameter list. - The body return type
V, if non-void, determines the type of anadditional state variable of the loop.The body must both accept a leading parameter and return a value of this typeV. - If
initis non-null, it must have return typeV.Its parameter list (of someform(A*)) must beeffectively identicalto the external parameter list(A...). - If
initisnull, the loop variable will be initialized to itsdefault value. - The parameter list of
start(of some form(A*)) must beeffectively identical to the external parameter list(A...). - Likewise, the parameter list of
endmust be effectively identicalto the external parameter list.
The resulting loop handle's result type and parameter signature are determined as follows:
- The loop handle's result type is the result type
Vof the body. - The loop handle's parameter types are the types
(A...),from the external parameter list.
Here is pseudocode for the resulting loop handle. In the code,
V/vrepresent the type / value ofthe second loop variable as well as the result type of the loop; andA.../a...representarguments passed to the loop.int start(A...);int end(A...);V init(A...);V body(V, int, A...);V countedLoop(A... a...) { int e = end(a...); int s = start(a...); V v = init(a...); for (int i = s; i < e; ++i) { v = body(v, i, a...); } return v;}- API Note:
- The implementation of this method can be expressed as follows:
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_predicate are handles to implementation-internal methods with // the following semantics: // MH_increment: (int limit, int counter) -> counter + 1 // MH_predicate: (int limit, int counter) -> counter < limit Class<?> counterType = start.type().returnType(); // int Class<?> returnType = body.type().returnType(); MethodHandle incr = MH_increment, pred = MH_predicate, retv = null; if (returnType != void.class) { // ignore the V variable incr = dropArguments(incr, 1, returnType); // (limit, v, i) => (limit, i) pred = dropArguments(pred, 1, returnType); // ditto retv = dropArguments(identity(returnType), 0, counterType); // ignore limit } body = dropArguments(body, 0, counterType); // ignore the limit variable MethodHandle[] loopLimit = { end, null, pred, retv }, // limit = end(); i < limit || return v bodyClause = { init, body }, // v = init(); v = body(v, i) indexVar = { start, incr }; // i = start(); i = i + 1 return loop(loopLimit, bodyClause, indexVar);} - Parameters:
start- a non-nullhandle to return the start value of the loop counter, which must beint. See above for other constraints.end- a non-nullhandle to return the end value of the loop counter (the loop will run toend-1). The result type must beint. See above for other constraints.init- optional initializer, providing the initial value of the loop variable. May benull, implying a default initial value. See above for other constraints.body- body of the loop, which may not benull. It controls the loop parameters and result type in the standard case (see above for details). It must accept its own return type (if non-void) plus anintparameter (for the counter), and may accept any number of additional types. See above for other constraints.- Returns:
- a method handle representing the loop.
- Throws:
NullPointerException- if any of thestart,end, orbodyhandles isnull.IllegalArgumentException- if any argument violates the rules formulated above.- Since:
- 9
- See Also:
- The
iteratedLoop
Constructs a loop that ranges over the values produced by anIterator<T>.This is a convenience wrapper for thegeneric loop combinator.The iterator itself will be determined by the evaluation of the
iteratorhandle.Each value it produces will be stored in a loop iteration variable of typeT.If the
bodyhandle returns a non-voidtypeV, a leading loop iteration variableof that type is also present. This variable is initialized using the optionalinithandle,or to thedefault value of typeVif that handle isnull.In each iteration, the iteration variables are passed to an invocation of the
bodyhandle.A non-voidvalue returned from the body (of typeV) updates the leadingiteration variable.The result of the loop handle execution will be the finalVvalue of that variable(orvoidif there is noVvariable).The following rules hold for the argument handles:
- The
bodyhandle must not benull; its type must be of the form(V T A...)V, whereVis non-void, or else(T A...)void.(In thevoidcase, we assign the typevoidto the nameV,and we will write(V T A...)Vwith the understanding that avoidtypeVis quietly dropped from the parameter list, leaving(T A...)V.) - The parameter list
(V T A...)of the body contributes to a listof types called theinternal parameter list.It will constrain the parameter lists of the other loop parts. - As a special case, if the body contributes only
VandTtypes,with no additionalAtypes, then the internal parameter list is extended bythe argument typesA...of theiteratorhandle; if it isnullthesingle typeIterableis added and constitutes theA...list. - If the iteration variable types
(V T)are dropped from the internal parameter list, the resulting shorterlist(A...)is called theexternal parameter list. - The body return type
V, if non-void, determines the type of anadditional state variable of the loop.The body must both accept a leading parameter and return a value of this typeV. - If
initis non-null, it must have return typeV.Its parameter list (of someform(A*)) must beeffectively identicalto the external parameter list(A...). - If
initisnull, the loop variable will be initialized to itsdefault value. - If the
iteratorhandle is non-null, it must have the returntypejava.util.Iteratoror a subtype thereof.The iterator it produces when the loop is executed will be assumedto yield values which can be converted to typeT. - The parameter list of an
iteratorthat is non-null(of some form(A*)) must beeffectively identical to the external parameter list(A...). - If
iteratorisnullit defaults to a method handle which behaveslikeIterable.iterator(). In that case, the internal parameter list(V T A...)must have at least oneAtype, and the default iteratorhandle parameter is adjusted to accept the leadingAtype, as if bytheasTypeconversion method.The leadingAtype must beIterableor a subtype thereof.This conversion step, done at loop construction time, must not throw aWrongMethodTypeException.
The type
Tmay be either a primitive or reference.Since typeIterator<T>is erased in the method handle representation to the raw typeIterator,theiteratedLoopcombinator adjusts the leading argument type forbodytoObjectas if by theasTypeconversion method.Therefore, if an iterator of the wrong type appears as the loop is executed, runtime exceptions may occuras the result of dynamic conversions performed byMethodHandle.asType(MethodType).The resulting loop handle's result type and parameter signature are determined as follows:
- The loop handle's result type is the result type
Vof the body. - The loop handle's parameter types are the types
(A...),from the external parameter list.
Here is pseudocode for the resulting loop handle. In the code,
V/vrepresent the type / value ofthe loop variable as well as the result type of the loop;T/t, that of the elements of thestructure the loop iterates over, andA.../a...represent arguments passed to the loop.Iterator<T> iterator(A...); // defaults to Iterable::iteratorV init(A...);V body(V,T,A...);V iteratedLoop(A... a...) { Iterator<T> it = iterator(a...); V v = init(a...); while (it.hasNext()) { T t = it.next(); v = body(v, t, a...); } return v;}- API Note:
- Example:, The implementation of this method can be expressed approximately as follows:
// get an iterator from a liststatic List<String> reverseStep(List<String> r, String e) { r.add(0, e); return r;}static List<String> newArrayList() { return new ArrayList<>(); }// assume MH_reverseStep and MH_newArrayList are handles to the above methodsMethodHandle 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));MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) { // assume MH_next, MH_hasNext, MH_startIter are handles to methods of Iterator/Iterable Class<?> returnType = body.type().returnType(); Class<?> ttype = body.type().parameterType(returnType == void.class ? 0 : 1); MethodHandle nextVal = MH_next.asType(MH_next.type().changeReturnType(ttype)); MethodHandle retv = null, step = body, startIter = iterator; if (returnType != void.class) { // the simple thing first: in (I V A...), drop the I to get V retv = dropArguments(identity(returnType), 0, Iterator.class); // body type signature (V T A...), internal loop types (I V A...) step = swapArguments(body, 0, 1); // swap V <-> T } if (startIter == null) startIter = MH_getIter; MethodHandle[] iterVar = { startIter, null, MH_hasNext, retv }, // it = iterator; while (it.hasNext()) bodyClause = { init, filterArguments(step, 0, nextVal) }; // v = body(v, t, a) return loop(iterVar, bodyClause);} - Parameters:
iterator- an optional handle to return the iterator to start the loop. If non-null, the handle must returnIteratoror a subtype. See above for other constraints.init- optional initializer, providing the initial value of the loop variable. May benull, implying a default initial value. See above for other constraints.body- body of the loop, which may not benull. It controls the loop parameters and result type in the standard case (see above for details). It must accept its own return type (if non-void) plus aTparameter (for the iterated values), and may accept any number of additional types. See above for other constraints.- Returns:
- a method handle embodying the iteration loop functionality.
- Throws:
NullPointerException- if thebodyhandle isnull.IllegalArgumentException- if any argument violates the above requirements.- Since:
- 9
- The
tryFinally
Makes a method handle that adapts atargetmethod handle by wrapping it in atry-finallyblock.Another method handle,cleanup, represents the functionality of thefinallyblock. Any exceptionthrown during the execution of thetargethandle will be passed to thecleanuphandle. Theexception will be rethrown, unlesscleanuphandle throws an exception first. Thevalue returned from thecleanuphandle's execution will be the result of the execution of thetry-finallyhandle.The
cleanuphandle will be passed one or two additional leading arguments.The first is the exception thrown during theexecution of thetargethandle, ornullif no exception was thrown.The second is the result of the execution of thetargethandle, or, if it throws an exception,anull, zero, orfalsevalue of the required type is supplied as a placeholder.The second argument is not present if thetargethandle has avoidreturn type.(Note that, except for argument type conversions, combinators representvoidvalues in parameter listsby omitting the corresponding paradoxical arguments, not by insertingnullor zero values.)The
targetandcleanuphandles must have the same corresponding argument and return types, exceptthat thecleanuphandle may omit trailing arguments. Also, thecleanuphandle must have one ortwo extra leading parameters:- a
Throwable, which will carry the exception thrown by thetargethandle (if any); and - a parameter of the same type as the return type of both
targetandcleanup, which will carrythe result from the execution of thetargethandle.This parameter is not present if thetargetreturnsvoid.
The pseudocode for the resulting adapter looks as follows. In the code,
Vrepresents the result type ofthetry/finallyconstruct;A/a, the types and values of arguments to the resultinghandle consumed by the cleanup; andB/b, those of arguments to the resulting handle discarded bythe 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) cannotbe modified by execution of the target, and so are passed unchangedfrom the caller to the cleanup, if it is invoked.The target and cleanup must return the same type, even if the cleanupalways throws.To create such a throwing cleanup, compose the cleanup logicwith
throwException,in order to create a method handle of the correct return type.Note that
tryFinallynever converts exceptions into normal returns.In rare cases where exceptions must be converted in that way, first wrapthe target withcatchException(MethodHandle, Class, MethodHandle)to capture an outgoing exception, and then wrap withtryFinally.It is recommended that the first parameter type of
cleanupbedeclaredThrowablerather than a narrower subtype. This ensurescleanupwill always be invoked with whatever exception thattargetthrows. Declaring a narrower type may result in aClassCastExceptionbeing thrown by thetry-finallyhandle if the type of the exception thrown bytargetis notassignable to the first parameter type ofcleanup. Note thatvarious exception types ofVirtualMachineError,LinkageError, andRuntimeExceptioncan in principle bethrown by almost any kind of Java code, and a finally clause thatcatches (say) onlyIOExceptionwould mask any of the othersbehind aClassCastException.- Parameters:
target- the handle whose execution is to be wrapped in atryblock.cleanup- the handle that is invoked in the finally block.- Returns:
- a method handle embodying the
try-finallyblock composed of the two arguments. - Throws:
NullPointerException- if any argument is nullIllegalArgumentException- ifcleanupdoes 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:
- a
tableSwitch
Creates a table switch method handle, which can be used to switch over a set of targetmethod handles, based on a given target index, called selector.For a selector value of
n, wherenfalls in the range[0, N),and whereNis the number of target method handles, the table switch methodhandle will invoke the n-th target method handle from the list of target method handles.For a selector value that does not fall in the range
[0, N), the table switchmethod handle will invoke the given fallback method handle.All method handles passed to this method must have the same type, with the additionalrequirement that the leading parameter be of type
int. The leading parameterrepresents the selector.Any trailing parameters present in the type will appear on the returned table switchmethod handle as well. Any arguments assigned to these parameters will be forwarded,together with the selector value, to the selected method handle when invoking it.
- API Note:
- Example:The cases each drop the
selectorvalue they are given, and take an additionalStringargument, which is concatenated (usingString.concat(String))to a specific constant label string for each case:MethodHandles.Lookup lookup = MethodHandles.lookup();MethodHandle caseMh = lookup.findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));caseMh = MethodHandles.dropArguments(caseMh, 0, int.class);MethodHandle caseDefault = MethodHandles.insertArguments(caseMh, 1, "default: ");MethodHandle case0 = MethodHandles.insertArguments(caseMh, 1, "case 0: ");MethodHandle case1 = MethodHandles.insertArguments(caseMh, 1, "case 1: ");MethodHandle mhSwitch = MethodHandles.tableSwitch( caseDefault, case0, case1);assertEquals("default: data", (String) mhSwitch.invokeExact(-1, "data"));assertEquals("case 0: data", (String) mhSwitch.invokeExact(0, "data"));assertEquals("case 1: data", (String) mhSwitch.invokeExact(1, "data"));assertEquals("default: data", (String) mhSwitch.invokeExact(2, "data")); - Parameters:
fallback- the fallback method handle that is called when the selector is not within the range[0, N).targets- array of target method handles.- Returns:
- the table switch method handle.
- Throws:
NullPointerException- iffallback, thetargetsarray, or any any of the elements of thetargetsarray arenull.IllegalArgumentException- if thetargetsarray is empty, if the leading parameter of the fallback handle or any of the target handles is notint, or if the types of the fallback handle and all of target handles are not the same.- Since:
- 17
filterValue
public static VarHandle filterValue(VarHandle target,MethodHandle filterToTarget,MethodHandle filterFromTarget) Adapts a target var handle by pre-processing incoming and outgoing values using a pair of filter functions.When calling e.g.
VarHandle.set(Object...)on the resulting var handle, the incoming value (of typeT, whereTis thelast parameter type of the first filter function) is processed using the first filter and then passedto the target var handle.Conversely, when calling e.g.VarHandle.get(Object...)on the resulting var handle, the return value obtained fromthe target var handle (of typeT, whereTis thelast parameter type of the second filter function)is processed using the second filter and returned to the caller. More advanced access mode types, such asVarHandle.AccessMode.COMPARE_AND_EXCHANGEmight apply both filters at the same time.For the boxing and unboxing filters to be well-formed, their types must be of the form
(A... , S) -> Tand(A... , T) -> S, respectively, whereTis the type of the target var handle. If this is the case,the resulting var handle will have typeSand will feature the additional coordinatesA...(whichwill be appended to the coordinates of the target var handle).If the boxing and unboxing filters throw any checked exceptions when invoked, the resulting var handle willthrow an
IllegalStateException.The resulting var handle will feature the same access modes (see
VarHandle.AccessMode) andatomic access guarantees as those featured by the target var handle.- Parameters:
target- the target var handlefilterToTarget- a filter to convert some typeSinto the type oftargetfilterFromTarget- a filter to convert the type oftargetto some typeS- Returns:
- an adapter var handle which accepts a new type, performing the provided boxing/unboxing conversions.
- Throws:
IllegalArgumentException- iffilterFromTargetandfilterToTargetare not well-formed, that is, they have typesother than(A... , S) -> Tand(A... , T) -> S, respectively, whereTis the type of the target var handle,or if it's determined that eitherfilterFromTargetorfilterToTargetthrows any checked exceptions.NullPointerException- if any of the arguments isnull.- Since:
- 22
filterCoordinates
Adapts a target var handle by pre-processing incoming coordinate values using unary filter functions.When calling e.g.
VarHandle.get(Object...)on the resulting var handle, the incoming coordinate valuesstarting at positionpos(of typeC1, C2 ... Cn, whereC1, C2 ... Cnare the return typesof the unary filter functions) are transformed into new values (of typeS1, S2 ... Sn, whereS1, S2 ... Snare theparameter types of the unary filter functions), and then passed (along with any coordinate that was left unalteredby the adaptation) to the target var handle.For the coordinate filters to be well-formed, their types must be of the form
S1 -> T1, S2 -> T1 ... Sn -> Tn,whereT1, T2 ... Tnare the coordinate types starting at positionposof the target var handle.If any of the filters throws a checked exception when invoked, the resulting var handle willthrow an
IllegalStateException.The resulting var handle will feature the same access modes (see
VarHandle.AccessMode) andatomic access guarantees as those featured by the target var handle.- Parameters:
target- the target var handlepos- the position of the first coordinate to be transformedfilters- the unary functions which are used to transform coordinates starting at positionpos- Returns:
- an adapter var handle which accepts new coordinate types, applying the provided transformationto the new coordinate values.
- Throws:
IllegalArgumentException- if the handles infiltersare not well-formed, that is, they have typesother thanS1 -> T1, S2 -> T2, ... Sn -> TnwhereT1, T2 ... Tnare the coordinate types startingat positionposof the target var handle, ifposis not between 0 and the target var handle coordinate arity, inclusive,or if more filters are provided than the actual number of coordinate types available starting atpos,or if it's determined that any of the filters throws any checked exceptions.NullPointerException- if any of the arguments isnullorfilterscontainsnull.- Since:
- 22
insertCoordinates
Provides a target var handle with one or morebound coordinatesin advance of the var handle's invocation. As a consequence, the resulting var handle will feature lesscoordinate types than the target var handle.When calling e.g.
VarHandle.get(Object...)on the resulting var handle, incoming coordinate valuesare joined with bound coordinate values, and then passed to the target var handle.For the bound coordinates to be well-formed, their types must be
T1, T2 ... Tn,whereT1, T2 ... Tnare the coordinate types starting at positionposof the target var handle.The resulting var handle will feature the same access modes (see
VarHandle.AccessMode) andatomic access guarantees as those featured by the target var handle.- Parameters:
target- the var handle to invoke after the bound coordinates are insertedpos- the position of the first coordinate to be insertedvalues- the series of bound coordinates to insert- Returns:
- an adapter var handle which inserts additional coordinates, before calling the target var handle
- Throws:
IllegalArgumentException- ifposis not between 0 and the target var handle coordinate arity, inclusive,or if more values are provided than the actual number of coordinate types available starting atpos.ClassCastException- if the bound coordinates invaluesare not well-formed, that is, they have typesother thanT1, T2 ... Tn, whereT1, T2 ... Tnare the coordinate types starting at positionposof the target var handle.NullPointerException- if any of the arguments isnullorvaluescontainsnull.- Since:
- 22
permuteCoordinates
public static VarHandle permuteCoordinates(VarHandle target,List<Class<?>> newCoordinates, int... reorder) Provides a var handle which adapts the coordinate values of the target var handle, by re-arranging themso that the new coordinates match the provided ones.The given array controls the reordering.Call
#Ithe number of incoming coordinates (the valuenewCoordinates.size()), and call#Othe numberof outgoing coordinates (the number of coordinates associated with the target var handle).Then the length of the reordering array must be#O,and each element must be a non-negative number less than#I.For everyNless than#O, theN-thoutgoing coordinate will be taken from theI-th incomingcoordinate, whereIisreorder[N].No coordinate value conversions are applied.The type of each incoming coordinate, as determined by
newCoordinates,must be identical to the type of the corresponding outgoing coordinatein the target var handle.The reordering array need not specify an actual permutation.An incoming coordinate will be duplicated if its index appearsmore than once in the array, and an incoming coordinate will be droppedif its index does not appear in the array.
The resulting var handle will feature the same access modes (see
VarHandle.AccessMode) andatomic access guarantees as those featured by the target var handle.- Parameters:
target- the var handle to invoke after the coordinates have been reorderednewCoordinates- the new coordinate typesreorder- an index array which controls the reordering- Returns:
- an adapter var handle which re-arranges the incoming coordinate values,before calling the target var handle
- Throws:
IllegalArgumentException- if the index array length is not equal tothe number of coordinates of the target var handle, or if any index array element is not a valid index fora coordinate ofnewCoordinates, or if two corresponding coordinate types inthe target var handle and innewCoordinatesare not identical.NullPointerException- if any of the arguments isnullornewCoordinatescontainsnull.- Since:
- 22
collectCoordinates
Adapts a target var handle by pre-processinga sub-sequence of its coordinate values with a filter (a method handle).The pre-processed coordinates are replaced by the result (if any) of thefilter function and the target var handle is then called on the modified (usually shortened)coordinate list.If
Ris the return type of the filter, then:- if
Ris notvoid, the target var handle must have a coordinate of typeRinpositionpos. The parameter types of the filter will replace the coordinate type at positionposof the target var handle. When the returned var handle is invoked, it will be as if the filter is invoked first,and its result is passed in place of the coordinate at positionposin a downstream invocation of thetarget var handle. - if
Risvoid, the parameter types (if any) of the filter will be inserted in thecoordinate type list of the target var handle at positionpos. In this case, when the returned var handleis invoked, the filter essentially acts as a side effect, consuming some of the coordinate values, before adownstream invocation of the target var handle.
If any of the filters throws a checked exception when invoked, the resulting var handle willthrow an
IllegalStateException.The resulting var handle will feature the same access modes (see
VarHandle.AccessMode) andatomic access guarantees as those featured by the target var handle.- Parameters:
target- the var handle to invoke after the coordinates have been filteredpos- the position in the coordinate list of the target var handle where the filter is to be insertedfilter- the filter method handle- Returns:
- an adapter var handle which filters the incoming coordinate values,before calling the target var handle
- Throws:
IllegalArgumentException- if the return type offilteris not void, and it is not the same as theposcoordinate of the target var handle,ifposis not between 0 and the target var handle coordinate arity, inclusive,if the resulting var handle's type would havetoo many coordinates,or if it's determined thatfilterthrows any checked exceptions.NullPointerException- if any of the arguments isnull.- Since:
- 22
- if
dropCoordinates
Returns a var handle which will discard some dummy coordinates before delegating to thetarget var handle. As a consequence, the resulting var handle will feature morecoordinate types than the target var handle.The
posargument may range between zero andN, whereN is the arity of thetarget var handle's coordinate types. Ifposis zero, the dummy coordinates will precedethe target's real arguments; ifposisN they will come after.The resulting var handle will feature the same access modes (see
VarHandle.AccessMode) andatomic access guarantees as those featured by the target var handle.- Parameters:
target- the var handle to invoke after the dummy coordinates are droppedpos- position of the first coordinate to drop (zero for the leftmost)valueTypes- the type(s) of the coordinate(s) to drop- Returns:
- an adapter var handle which drops some dummy coordinates, before calling the target var handle
- Throws:
IllegalArgumentException- ifposis not between 0 and the target var handle coordinate arity, inclusive.NullPointerException- if any of the arguments isnullorvalueTypescontainsnull.- Since:
- 22