模块 java.base

类 MethodHandles

java.lang.Object
java.lang.invoke.MethodHandles

public class MethodHandles extends Object
此类仅包含对方法句柄进行操作或返回方法句柄的静态方法。它们分为几类:
  • 有助于为方法和字段创建方法句柄的查找方法。
  • 组合器方法,将预先存在的方法句柄组合或转换为新的方法句柄。
  • 用于创建模拟其他常见 JVM 操作或控制流模式的方法句柄的其他工厂方法。
如果创建的方法句柄的类型为 太多的参数,则查找、组合器或工厂方法将失败并抛出 IllegalArgumentException
自从:
1.7
  • 方法详情

    • lookup

      public static MethodHandles.Lookup  lookup()
      返回具有完整功能的 lookup object 来模拟调用者所有支持的字节码行为。这些功能包括对调用者的 完全权限访问。查找对象上的工厂方法可以为调用者可以通过字节码访问的任何成员创建直接方法句柄,包括受保护和私有字段和方法。此查找对象由原始查找类创建,并设置了 ORIGINAL 位。这个查找对象是一个capability,可以委托给受信任的代理。不要将它存储在不受信任的代码可以访问它的地方。

      此方法对调用者敏感,这意味着它可能会向不同的调用者返回不同的值。如果 MethodHandles.lookup 是从堆栈上没有调用者框架的上下文调用的(例如,当直接从 JNI 附加线程调用时),则抛出 IllegalCallerException。要在此类上下文中获取 lookup object ,请使用将隐式标识为调用方的辅助类,或使用 publicLookup() 获取低权限查找。

      返回:
      此方法的调用者的查找对象,带有 原来的完全权限访问
      抛出:
      IllegalCallerException - 如果堆栈上没有调用者帧。
    • publicLookup

      public static MethodHandles.Lookup  publicLookup()
      返回最低信任度的 lookup object 。查找具有 UNCONDITIONAL 模式。它只能用于为无条件导出的包中的公共类的公共成员创建方法句柄。

      作为一个纯粹的约定,这个查找对象的 查找类 将是 Object

      API 注意:
      Object 的使用是常规的,并且因为查找模式是有限的,所以没有提供对 Object 内部、它的包或它的模块的特殊访问。此公共查找对象或其他具有 UNCONDITIONAL 模式的查找对象假定可读性。因此,查找类不用于确定查找上下文。

      Discussion: 可以使用 publicLookup().in(C.class) 形式的表达式将查找类更改为任何其他类 C。公共查找对象始终受 安全经理检查 约束。此外,它无法访问 调用者敏感方法

      返回:
      最低限度信任的查找对象
    • privateLookupIn

      public static MethodHandles.Lookup  privateLookupIn(Class <?> targetClass, MethodHandles.Lookup  caller) throws IllegalAccessException
      返回目标类上的 lookup 对象以模拟所有支持的字节码行为,包括 私人访问 。返回的查找对象可以提供对模块和包中的类以及这些类的成员的访问,在 Java 访问控制的正常规则之外,而不是符合模块化 deep reflection 更宽松的规则。

      当且仅当以下所有条件都是 true 时,允许在模块 M1 中指定为 Lookup 对象的调用者对模块 M2 和目标类的包进行深度反射:

      • 如果有security manager,调用它的checkPermission方法检查ReflectPermission("suppressAccessChecks"),必须正常返回。
      • 调用者查找对象必须有 完全权限访问 。具体来说:
        • 调用者查找对象必须具有 MODULE 查找模式。 (这是因为否则将无法确保原始查找创建者是任何特定模块的成员,因此任何后续的可读性和合格导出检查都将变得无效。)
        • 调用者查找对象必须具有 PRIVATE 访问权限。 (这是因为打算单独使用 MODULE 共享模块内访问的应用程序会无意中也共享对其自己模块的深度反射。)
      • 目标类必须是适当的类,而不是原始类或数组类。 (因此,M2 是明确定义的。)
      • 如果调用方模块 M1 与目标模块 M2 不同,则以下两项必须为真:

      如果违反了上述任何检查,此方法将失败并出现异常。

      否则,如果 M1M2 是同一个模块,则此方法返回 Lookup on targetClass with 完全权限访问 with null previous lookup class。

      否则,M1M2 是两个不同的模块。此方法在 targetClass 上返回一个 Lookup,它将调用者的查找类记录为具有 PRIVATE 访问权限但没有 MODULE 访问权限的新的先前查找类。

      生成的 Lookup 对象没有 ORIGINAL 访问权限。

      参数:
      targetClass - 目标类
      caller - 调用者查找对象
      返回:
      目标类的查找对象,具有私有访问权限
      抛出:
      IllegalArgumentException - 如果 targetClass 是原始类型或 void 或数组类
      NullPointerException - 如果 targetClasscallernull
      SecurityException - 如果安全经理拒绝
      IllegalAccessException - 如果上面指定的任何其他访问检查失败
      自从:
      9
      参见:
    • classData

      public static <T> T classData(MethodHandles.Lookup  caller, String  name, Class <T> type) throws IllegalAccessException
      返回与给定 caller 查找对象或 null 的查找类关联的 class data

      可以通过调用 Lookup::defineHiddenClassWithClassData 创建具有类数据的隐藏类。如果给定的 caller 查找对象的查找类尚未初始化,则此方法将导致执行静态类初始化程序。

      Lookup::defineHiddenClass 创建的隐藏类和非隐藏类没有类数据。如果在这些类的查找对象上调用此方法,则返回 null

      此查找的 查找模式 必须具有 原始访问 才能检索类数据。

      API 注意:
      此方法可以称为动态计算常量的引导方法。框架可以使用类数据创建隐藏类,例如可以是 ClassMethodHandle 对象。类数据只能由原始调用者创建的查找对象访问,但同一嵌套中的其他成员无法访问。如果框架通过类数据将安全敏感对象传递给隐藏类,建议将类数据的值加载为动态计算的常量,而不是将类数据存储在其他同组成员可以访问的私有静态字段中。
      类型参数:
      T - 将类数据对象转换为的类型
      参数:
      caller - 描述执行操作的类的查找上下文(通常由 JVM 堆叠)
      name - 必须是 ConstantDescs.DEFAULT_NAME ("_")
      type - 类数据的类型
      返回:
      类数据的值(如果存在于查找类中);否则null
      抛出:
      IllegalArgumentException - 如果名称不是 "_"
      IllegalAccessException - 如果查找上下文没有 原来的 访问权限
      ClassCastException - 如果类数据不能转换为给定的 type
      NullPointerException - 如果 callertype 参数是 null
      Java 虚拟机规范:
      5.5 初始化
      自从:
      16
      参见:
    • classDataAt

      public static <T> T classDataAt(MethodHandles.Lookup  caller, String  name, Class <T> type, int index) throws IllegalAccessException
      如果与给定 caller 查找对象的查找类关联的类数据是 List ,则返回 类数据 中指定索引处的元素。如果此查找类中不存在类数据,则此方法返回 null

      可以通过调用 Lookup::defineHiddenClassWithClassData 创建具有类数据的隐藏类。如果给定的 caller 查找对象的查找类尚未初始化,则此方法将导致执行静态类初始化程序。

      Lookup::defineHiddenClass 创建的隐藏类和非隐藏类没有类数据。如果在这些类的查找对象上调用此方法,则返回 null

      此查找的 查找模式 必须具有 原始访问 才能检索类数据。

      API 注意:
      此方法可以称为动态计算常量的引导方法。框架可以创建一个带有类数据的隐藏类,例如可以List.of(o1, o2, o3....)包含多个对象,并使用此方法在特定索引处加载一个元素。类数据只能由原始调用者创建的查找对象访问,但同一嵌套中的其他成员无法访问。如果框架通过类数据将安全敏感对象传递给隐藏类,建议将类数据的值加载为动态计算的常量,而不是将类数据存储在其他同组成员可以访问的私有静态字段中。
      类型参数:
      T - 将结果对象转换为的类型
      参数:
      caller - 描述执行操作的类的查找上下文(通常由 JVM 堆叠)
      name - 必须是 ConstantDescs.DEFAULT_NAME ("_")
      type - 类数据中给定索引处的元素类型
      index - 类数据中元素的索引
      返回:
      如果存在类数据,则为类数据中给定索引处的元素;否则null
      抛出:
      IllegalArgumentException - 如果名称不是 "_"
      IllegalAccessException - 如果查找上下文没有 原来的 访问权限
      ClassCastException - 如果类数据无法转换为 List 或指定索引处的元素无法转换为给定类型
      IndexOutOfBoundsException - 如果索引超出范围
      NullPointerException - 如果 callertype 参数是 null ;或者如果拆箱操作失败,因为给定索引处的元素是 null
      自从:
      16
      参见:
    • reflectAs

      public static <T extends Member > T reflectAs(Class <T> expected, MethodHandle  target)
      直接方法句柄 执行未经检查的“破解”。结果就好像用户获得了一个足以破解目标方法句柄的查找对象,在目标上调用 Lookup.revealDirect 来获取它的符号引用,然后调用 MethodHandleInfo.reflectAs 来解析对成员的符号引用。

      如果有安全管理器,它的 checkPermission 方法将以 ReflectPermission("suppressAccessChecks") 权限调用。

      类型参数:
      T - 所需的结果类型,Member 或子类型
      参数:
      expected - 表示所需结果类型的类对象 T
      target - 破解符号引用组件的直接方法句柄
      返回:
      对方法、构造方法或字段对象的引用
      抛出:
      SecurityException - 如果调用者无权调用 setAccessible
      NullPointerException - 如果任一参数是 null
      IllegalArgumentException - 如果目标不是直接方法句柄
      ClassCastException - 如果成员不是预期类型
      自从:
      1.8
    • arrayConstructor

      public static MethodHandle  arrayConstructor(Class <?> arrayClass) throws IllegalArgumentException
      生成一个方法句柄来构造所需类型的数组,就像通过 anewarray 字节码一样。方法句柄的返回类型将是数组类型。其唯一参数的类型将是 int ,它指定数组的大小。

      如果使用负数组大小调用返回的方法句柄,将抛出 NegativeArraySizeException

      参数:
      arrayClass - 数组类型
      返回:
      可以创建给定类型数组的方法句柄
      抛出:
      NullPointerException - 如果参数是 null
      IllegalArgumentException - 如果 arrayClass 不是数组类型
      Java 虚拟机规范:
      6.5anewarray指令
      自从:
      9
      参见:
    • arrayLength

      public static MethodHandle  arrayLength(Class <?> arrayClass) throws IllegalArgumentException
      生成一个返回数组长度的方法句柄,就像由 arraylength 字节码一样。方法句柄的类型将 int 作为返回类型,其唯一参数将是数组类型。

      如果使用 null 数组引用调用返回的方法句柄,将抛出 NullPointerException

      参数:
      arrayClass - 数组类型
      返回:
      一个方法句柄,它可以检索给定数组类型的数组的长度
      抛出:
      NullPointerException - 如果参数是 null
      IllegalArgumentException - 如果 arrayClass 不是数组类型
      Java 虚拟机规范:
      6.5arraylength指令
      自从:
      9
    • arrayElementGetter

      public static MethodHandle  arrayElementGetter(Class <?> arrayClass) throws IllegalArgumentException
      生成一个方法句柄,提供对数组元素的读取访问权限,就像通过 aaload 字节码一样。方法句柄的类型将具有数组元素类型的返回类型。它的第一个参数是数组类型,第二个参数是 int

      调用返回的方法句柄时,将检查数组引用和数组索引。如果数组引用是 null,将抛出 NullPointerException;如果索引为负或大于或等于数组的长度,将抛出 ArrayIndexOutOfBoundsException

      参数:
      arrayClass - 数组类型
      返回:
      可以从给定数组类型加载值的方法句柄
      抛出:
      NullPointerException - 如果参数为空
      IllegalArgumentException - 如果 arrayClass 不是数组类型
      Java 虚拟机规范:
      6.5aaload指令
    • arrayElementSetter

      public static MethodHandle  arrayElementSetter(Class <?> arrayClass) throws IllegalArgumentException
      生成一个方法句柄,提供对数组元素的写访问权限,就像通过 astore 字节码一样。方法句柄的类型将具有 void 返回类型。它的最后一个参数将是数组的元素类型。第一个和第二个参数将是数组类型和 int。

      调用返回的方法句柄时,将检查数组引用和数组索引。如果数组引用是 null,将抛出 NullPointerException;如果索引为负或大于或等于数组的长度,将抛出 ArrayIndexOutOfBoundsException

      参数:
      arrayClass - 数组的类
      返回:
      可以将值存储到数组类型中的方法句柄
      抛出:
      NullPointerException - 如果参数为空
      IllegalArgumentException - 如果 arrayClass 不是数组类型
      Java 虚拟机规范:
      6.5aastore指令
    • arrayElementVarHandle

      public static VarHandle  arrayElementVarHandle(Class <?> arrayClass) throws IllegalArgumentException
      生成一个 VarHandle,可以访问类型为 arrayClass 的数组的元素。 VarHandle 的变量类型是 arrayClass 的组件类型,坐标类型列表是 (arrayClass, int),其中 int 坐标类型对应于作为数组索引的参数。

      在以下情况下,不支持返回的 VarHandle 的某些访问模式:

      • 如果组件类型不是 byteshortcharintlongfloatdouble,则不支持数字原子更新访问模式。
      • 如果组件类型不是 booleanbyteshortcharintlong,则不支持按位原子更新访问模式。

      如果组件类型是 floatdouble,则数字和原子更新访问模式使用它们的按位表示比较值(分别参见 Float.floatToRawIntBits(float) Double.doubleToRawLongBits(double) )。

      调用返回的 VarHandle 时,将检查数组引用和数组索引。如果数组引用是 null,将抛出 NullPointerException;如果索引为负或大于或等于数组的长度,将抛出 ArrayIndexOutOfBoundsException

      API 注意:
      float 值或 double 值的按位比较,由数字和原子更新访问模式执行,不同于原始 == 运算符以及 Float.equals(java.lang.Object) Double.equals(java.lang.Object) 方法,特别是比较 NaN 值或比较 -0.0+0.0 。在使用此类值执行比较和设置或比较和交换操作时应小心,因为操作可能会意外失败。有许多可能的 NaN 值在 Java 中被认为是 NaN,尽管 Java 提供的 IEEE 754 浮点运算无法区分它们。如果预期或见证值是 NaN 值并且它被转换(可能以特定于平台的方式)为另一个 NaN 值,并且因此具有不同的按位表示(请参阅 Float.intBitsToFloat(int) Double.longBitsToDouble(long) 了解更多详细信息),则可能会发生操作失败。值 -0.0+0.0 具有不同的按位表示,但在使用原始 == 运算符时被视为相等。例如,如果数字算法计算的预期值为 -0.0 并且先前计算的见证值为 +0.0 ,则可能会发生操作失败。
      参数:
      arrayClass - 数组的类,类型为 T[]
      返回:
      可以访问数组元素的 VarHandle
      抛出:
      NullPointerException - 如果 arrayClass 为空
      IllegalArgumentException - 如果 arrayClass 不是数组类型
      自从:
      9
    • byteArrayViewVarHandle

      public static VarHandle  byteArrayViewVarHandle(Class <?> viewArrayClass, ByteOrder  byteOrder) throws IllegalArgumentException
      生成一个 VarHandle,可以访问 byte[] 数组的元素,就像它是不同的原始数组类型一样,例如 int[]long[] 。 VarHandle 的变量类型是 viewArrayClass 的组件类型,坐标类型列表是 (byte[], int),其中 int 坐标类型对应于一个参数,该参数是 byte[] 数组的索引。返回的 VarHandle 访问 byte[] 数组中的索引处的字节,根据给定的字节序将字节组合到或从 viewArrayClass 的组件类型的值。

      支持的组件类型(变量类型)是 shortcharintlongfloatdouble

      如果索引小于 0 或大于 byte[] 数组长度减去 T 的大小(以字节为单位),则访问给定索引处的字节将导致 ArrayIndexOutOfBoundsException

      T 在索引处访问字节可能对齐或未对齐,相对于与数组和索引关联的底层内存地址,比如 A。如果访问未对齐,则对 getset 访问模式以外的任何访问都将导致 IllegalStateException 。在这种情况下,原子访问只能保证 A 的 GCD 和 T 的大小(以字节为单位)的最大幂次方。如果访问对齐,则支持以下访问模式并保证支持原子访问:

      • 所有T的读写访问模式,32位平台上longdouble的访问模式getset除外。
      • intlongfloatdouble 的原子更新访问模式。 (JDK 的未来主要平台版本可能支持某些当前不支持的访问模式的其他类型。)
      • intlong 的数字原子更新访问模式。 (JDK 的未来主要平台版本可能支持某些当前不支持的访问模式的其他数字类型。)
      • intlong 的按位原子更新访问模式。 (JDK 的未来主要平台版本可能支持某些当前不支持的访问模式的其他数字类型。)

      可以在不对特定数组进行操作的情况下为 byte[] 数组确定未对齐的访问,从而保证原子性。给定 indexT 及其对应的盒装类型 T_BOX ,可以按如下方式确定未对齐:

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

      如果变量类型是 floatdouble,则原子更新访问模式使用它们的按位表示比较值(分别参见 Float.floatToRawIntBits(float) Double.doubleToRawLongBits(double) )。

      参数:
      viewArrayClass - 视图数组类,组件类型为 T
      byteOrder - 视图数组元素的字节顺序,存储在底层 byte 数组中
      返回:
      一个 VarHandle,可以访问 byte[] 数组的元素,被视为与视图数组类的组件类型相对应的元素
      抛出:
      NullPointerException - 如果 viewArrayClass 或 byteOrder 为空
      IllegalArgumentException - 如果 viewArrayClass 不是数组类型
      UnsupportedOperationException - 如果不支持将 viewArrayClass 的组件类型作为变量类型
      自从:
      9
    • byteBufferViewVarHandle

      public static VarHandle  byteBufferViewVarHandle(Class <?> viewArrayClass, ByteOrder  byteOrder) throws IllegalArgumentException
      生成一个 VarHandle,允许访问 ByteBuffer 的元素,将其视为与 byte 不同的基本组件类型的元素数组,例如 int[]long[]。 VarHandle 的变量类型是 viewArrayClass 的组件类型,坐标类型列表是 (ByteBuffer, int),其中 int 坐标类型对应于一个参数,该参数是 byte[] 数组的索引。返回的 VarHandle 访问 ByteBuffer 中的索引处的字节,根据给定的字节顺序将字节组成到或从 viewArrayClass 的组件类型的值。

      支持的组件类型(变量类型)是 shortcharintlongfloatdouble

      如果 ByteBuffer 是只读的,则访问将导致 ReadOnlyBufferException 除了读取访问模式之外的任何内容。

      如果索引小于 0 或大于 ByteBuffer 限制减去 T 的大小(以字节为单位),则访问给定索引处的字节将导致 IndexOutOfBoundsException

      T 在索引处访问字节可能对齐或未对齐,相对于底层内存地址,比如 A,与 ByteBuffer 和索引相关联。如果访问未对齐,则对 getset 访问模式以外的任何访问都将导致 IllegalStateException 。在这种情况下,原子访问只能保证 A 的 GCD 和 T 的大小(以字节为单位)的最大幂次方。如果访问对齐,则支持以下访问模式并保证支持原子访问:

      • 所有T的读写访问模式,32位平台上longdouble的访问模式getset除外。
      • intlongfloatdouble 的原子更新访问模式。 (JDK 的未来主要平台版本可能支持某些当前不支持的访问模式的其他类型。)
      • intlong 的数字原子更新访问模式。 (JDK 的未来主要平台版本可能支持某些当前不支持的访问模式的其他数字类型。)
      • intlong 的按位原子更新访问模式。 (JDK 的未来主要平台版本可能支持某些当前不支持的访问模式的其他数字类型。)

      可以为 ByteBufferbb(直接或其他方式)、indexT 及其相应的盒装类型 T_BOX 确定未对齐的访问,因此原子性保证,如下所示:

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

      如果变量类型是 floatdouble,则原子更新访问模式使用它们的按位表示比较值(分别参见 Float.floatToRawIntBits(float) Double.doubleToRawLongBits(double) )。

      参数:
      viewArrayClass - 视图数组类,组件类型为 T
      byteOrder - 存储在底层 ByteBuffer 中的视图数组元素的字节顺序(请注意,这会覆盖 ByteBuffer 的字节顺序)
      返回:
      一个 VarHandle,可以访问 ByteBuffer 的元素,被视为与视图数组类的组件类型相对应的元素
      抛出:
      NullPointerException - 如果 viewArrayClass 或 byteOrder 为空
      IllegalArgumentException - 如果 viewArrayClass 不是数组类型
      UnsupportedOperationException - 如果不支持将 viewArrayClass 的组件类型作为变量类型
      自从:
      9
    • spreadInvoker

      public static MethodHandle  spreadInvoker(MethodType  type, int leadingArgCount)
      生成一个方法句柄,它将调用给定 type 的任何方法句柄,给定数量的尾随参数替换为单个尾随 Object[] 数组。生成的调用程序将是一个带有以下参数的方法句柄:
      • 单个 MethodHandle 目标
      • 零个或多个前导值(由 leadingArgCount 计算)
      • 包含尾随参数的 Object[] 数组

      调用程序将调用其目标,就像调用带有指示的 typeinvoke 一样。也就是说,如果目标恰好是给定的 type ,它将表现得像 invokeExact ;否则它的行为就像 asType 用于将目标转换为所需的 type

      返回的调用程序的类型将不是给定的 type ,而是将除第一个 leadingArgCount 之外的所有参数替换为类型为 Object[] 的单个数组,这将是最终参数。

      在调用其目标之前,调用者将展开最终数组,根据需要应用引用转换,以及拆箱和加宽原始参数。如果在调用调用程序时提供的数组参数没有正确数量的元素,则调用程序将抛出 IllegalArgumentException 而不是调用目标。

      此方法等效于以下代码(尽管它可能更高效):

      MethodHandle invoker = MethodHandles.invoker(type);
      int spreadArgCount = type.parameterCount() - leadingArgCount;
      invoker = invoker.asSpreader(Object[].class, spreadArgCount);
      return invoker;
       
      此方法不会抛出反射或安全异常。
      参数:
      type - 所需的目标类型
      leadingArgCount - 固定参数的数量,不变地传递给目标
      返回:
      适合调用给定类型的任何方法句柄的方法句柄
      抛出:
      NullPointerException - 如果 type 为空
      IllegalArgumentException - 如果 leadingArgCount 不在从 0 到 type.parameterCount() 的范围内,或者如果生成的方法句柄的类型为 太多的参数
    • exactInvoker

      public static MethodHandle  exactInvoker(MethodType  type)
      生成一个特殊的 invoker method handle 可用于调用给定类型的任何方法句柄,就像通过 invokeExact 一样。生成的调用程序将具有与所需类型完全相同的类型,除了它将接受类型为 MethodHandle 的附加前导参数。

      此方法等效于以下代码(尽管它可能更有效):publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)

      Discussion: 调用程序方法句柄在使用未知类型的变量方法句柄时很有用。例如,要模拟对变量方法句柄 MinvokeExact 调用,提取其类型 T ,为 T 查找调用方法 X ,并调用调用方法,如 X.invoke(T, A...) 。 (调用 X.invokeExact 是行不通的,因为类型 T 是未知的。)如果需要传播、收集或其他参数转换,它们可以应用于调用程序 X 并在许多 M 方法句柄值上重复使用,只要它们与 X 的类型兼容。

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

      此方法不会抛出反射或安全异常。

      参数:
      type - 所需的目标类型
      返回:
      适合调用给定类型的任何方法句柄的方法句柄
      抛出:
      IllegalArgumentException - 如果生成的方法句柄的类型为 太多的参数
    • invoker

      public static MethodHandle  invoker(MethodType  type)
      产生一个特殊的 invoker method handle 可用于调用与给定类型兼容的任何方法句柄,就像通过 invoke 一样。生成的调用程序将具有与所需类型完全相同的类型,除了它将接受类型为 MethodHandle 的附加前导参数。

      在调用其目标之前,如果目标与预期类型不同,调用程序将根据需要应用引用强制转换,并对基本值进行装箱、拆箱或加宽,就像 asType 一样。同样,返回值将根据需要进行转换。如果目标是 变量 arity 方法句柄 ,则将进行所需的元数转换,就像 asType 一样。

      此方法等效于以下代码(尽管它可能更有效):publicLookup().findVirtual(MethodHandle.class, "invoke", type)

      Discussion: A 一般方法类型 是仅提及 Object 参数和返回值的一个。这种类型的调用者能够调用与通用类型具有相同数量的任何方法句柄。

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

      此方法不会抛出反射或安全异常。

      参数:
      type - 所需的目标类型
      返回:
      适用于调用可转换为给定类型的任何方法句柄的方法句柄
      抛出:
      IllegalArgumentException - 如果生成的方法句柄的类型为 太多的参数
    • varHandleExactInvoker

      public static MethodHandle  varHandleExactInvoker(VarHandle.AccessMode  accessMode, MethodType  type)
      生成一个特殊的 invoker method handle,它可用于在关联访问模式类型与给定类型兼容的任何 VarHandle 上调用签名多态访问模式方法。生成的调用程序将具有与所需的给定类型完全相同的类型,除了它将接受类型为 VarHandle 的附加前导参数。
      参数:
      accessMode - VarHandle 访问模式
      type - 所需的目标类型
      返回:
      适用于调用访问模式类型为给定类型的任何 VarHandle 的访问模式方法的方法句柄。
      自从:
      9
    • varHandleInvoker

      public static MethodHandle  varHandleInvoker(VarHandle.AccessMode  accessMode, MethodType  type)
      生成一个特殊的 invoker method handle,它可用于在关联访问模式类型与给定类型兼容的任何 VarHandle 上调用签名多态访问模式方法。生成的调用程序将具有与所需的给定类型完全相同的类型,除了它将接受类型为 VarHandle 的附加前导参数。

      在调用其目标之前,如果访问模式类型与所需的给定类型不同,则调用程序将根据需要应用引用强制转换,并对基本值进行装箱、拆箱或加宽,就像 asType 一样。同样,返回值将根据需要进行转换。

      此方法等效于以下代码(尽管它可能更有效):publicLookup().findVirtual(VarHandle.class, accessMode.name(), type)

      参数:
      accessMode - VarHandle 访问模式
      type - 所需的目标类型
      返回:
      适用于调用任何 VarHandle 的访问模式方法的方法句柄,其访问模式类型可转换为给定类型。
      自从:
      9
    • explicitCastArguments

      public static MethodHandle  explicitCastArguments(MethodHandle  target, MethodType  newType)
      生成一个方法句柄,它通过成对参数和返回类型转换使给定方法句柄的类型适应新类型。原始类型和新类型必须具有相同数量的参数。生成的方法句柄保证报告一个等于所需新类型的类型。

      如果原始类型和新类型相等,则返回目标。

      允许与 MethodHandle.asType 相同的转换,如果这些转换失败,也会应用一些额外的转换。给定类型 T0T1 ,如果可能,在 asType 完成的任何转换之前或代替应用以下转换之一:

      • 如果 T0T1 是引用,而 T1 是接口类型,则类型 T0 的值将作为 T1 传递,无需转换。 (这种接口处理遵循字节码验证器的用法。)
      • 如果 T0 是boolean而 T1 是另一个原语,则boolean将转换为字节值,1 表示真,0 表示假。 (此处理遵循字节码验证器的用法。)
      • 如果 T1 是 boolean 且 T0 是另一个原语,则 T0 通过 Java 强制转换 (JLS 5.5 ) 转换为字节,并测试结果的低位,就像 (x & 1) != 0 一样。
      • 如果 T0T1 是除boolean以外的原语,则应用 Java 强制转换 (JLS 5.5)。 (具体来说,T0 将通过加宽和/或变窄转换为 T1。)
      • 如果 T0 是引用而 T1 是基元,则将在运行时应用拆箱转换,可能随后对基元值进行 Java 强制转换(JLS 5.5 ),随后可能通过测试低阶从字节到boolean的转换少量。
      • 如果 T0 是引用而 T1 是原语,并且如果引用在运行时为空,则引入零值。
      参数:
      target - 重新键入参数后要调用的方法句柄
      newType - 新方法句柄的预期类型
      返回:
      一个方法句柄,在执行任何必要的参数转换后委托给目标,并安排任何必要的返回值转换
      抛出:
      NullPointerException - 如果任一参数为空
      WrongMethodTypeException - 如果无法进行转换
      参见:
    • permuteArguments

      public static MethodHandle  permuteArguments(MethodHandle  target, MethodType  newType, int... reorder)
      通过重新排序参数,生成一个方法句柄,该方法句柄将给定方法句柄的调用序列调整为新类型。生成的方法句柄保证报告一个等于所需新类型的类型。

      给定的数组控制重新排序。调用#I传入参数个数(值为newType.parameterCount(),调用#O传出参数个数(值为target.type().parameterCount())。则重排数组的长度必须为#O,且每个元素必须为小于#I的非负数. 对于每一个小于 #ON,第 N 个传出参数将从第 I 个传入参数中获取,其中 Ireorder[N]

      不应用参数或返回值转换。由 newType 确定的每个传入参数的类型必须与目标方法句柄中相应传出参数或参数的类型相同。 newType 的返回类型必须与原始目标的返回类型相同。

      重新排序的数组不需要指定实际的排列。如果传入参数的索引在数组中出现多次,则传入参数将被复制;如果传入参数的索引未出现在数组中,则传入参数将被删除。与 dropArguments 的情况一样,重新排序数组中未提及的传入参数可以是任何类型,仅由 newType 确定。

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

      Note: 结果适配器永远不是 变量方法句柄 ,即使原始目标方法句柄是。

      参数:
      target - 重新排序参数后要调用的方法句柄
      newType - 新方法句柄的预期类型
      reorder - 控制重新排序的索引数组
      返回:
      在删除未使用的参数并移动和/或复制其他参数后委托给目标的方法句柄
      抛出:
      NullPointerException - 如果任何参数为空
      IllegalArgumentException - 如果索引数组长度不等于目标的元数,或者如果任何索引数组元素不是 newType 参数的有效索引,或者如果 target.type()newType 中的两个相应参数类型不相同,
    • constant

      public static MethodHandle  constant(Class <?> type, Object  value)
      生成请求的返回类型的方法句柄,每次调用时返回给定的常量值。

      在返回方法句柄之前,将传入的值转换为请求的类型。如果请求的类型是原始类型,则尝试扩大原始类型转换,否则尝试引用转换。

      返回的方法句柄相当于 identity(type).bindTo(value)

      参数:
      type - 所需方法句柄的返回类型
      value - 要返回的值
      返回:
      给定返回类型的方法句柄,没有参数,它总是返回给定值
      抛出:
      NullPointerException - 如果 type 参数为空
      ClassCastException - 如果无法将值转换为所需的返回类型
      IllegalArgumentException - 如果给定类型是 void.class
    • identity

      public static MethodHandle  identity(Class <?> type)
      生成一个方法句柄,该句柄在调用时返回其唯一参数。
      参数:
      type - 唯一参数的类型和所需方法句柄的返回值
      返回:
      接受并返回给定类型的一元方法句柄
      抛出:
      NullPointerException - 如果参数为空
      IllegalArgumentException - 如果给定类型是 void.class
    • zero

      public static MethodHandle  zero(Class <?> type)
      生成所请求返回类型的常量方法句柄,每次调用时返回该类型的默认值。生成的常量方法句柄将没有副作用。

      返回的方法句柄相当于 empty(methodType(type)) 。它也等同于 explicitCastArguments(constant(Object.class, null), methodType(type)) ,因为 explicitCastArgumentsnull 转换为默认值。

      参数:
      type - 所需方法句柄的预期返回类型
      返回:
      一个常量方法句柄,它不带参数并返回给定类型的默认值(或 void,如果类型为 void)
      抛出:
      NullPointerException - 如果参数为空
      自从:
      9
      参见:
    • empty

      public static MethodHandle  empty(MethodType  type)
      生成请求类型的方法句柄,该句柄忽略任何参数,不执行任何操作,并根据返回类型返回合适的默认值。也就是说,它返回一个零原始值,一个 nullvoid

      返回的方法句柄相当于 dropArguments(zero(type.returnType()), 0, type.parameterList())

      API 注意:
      给定谓词和目标,可以生成有用的“if-then”结构,如 guardWithTest(pred, target, empty(target.type())
      参数:
      type - 所需方法句柄的类型
      返回:
      给定类型的常量方法句柄,它返回给定返回类型的默认值
      抛出:
      NullPointerException - 如果参数为空
      自从:
      9
      参见:
    • insertArguments

      public static MethodHandle  insertArguments(MethodHandle  target, int pos, Object ... values)
      在方法句柄调用之前为目标方法句柄提供一个或多个bound arguments。对应于绑定参数的目标的形式参数称为 bound parameters 。返回一个保存绑定参数的新方法句柄。当它被调用时,它接收任何非绑定参数的参数,将保存的参数绑定到它们的相应参数,并调用原始目标。

      新方法句柄的类型将从原始目标类型中删除绑定参数的类型,因为新方法句柄将不再需要其调用者提供这些参数。

      每个给定的参数对象必须匹配相应的绑定参数类型。如果绑定参数类型是原始类型,则参数对象必须是包装器,并且将被拆箱以生成原始值。

      pos 参数选择要绑定的参数。它的范围可能介于零和N-L(包括),其中N是目标方法句柄的元数,并且L是值数组的长度。

      Note: 结果适配器永远不是 变量方法句柄 ,即使原始目标方法句柄是。

      参数:
      target - 插入参数后要调用的方法句柄
      pos - 插入参数的位置(第一个为零)
      values - 要插入的参数系列
      返回:
      在调用原始方法句柄之前插入附加参数的方法句柄
      抛出:
      NullPointerException - 如果目标或 values 数组为空
      IllegalArgumentException - 如果 (@code pos) 小于 0 或大于 N - L,其中 N 是目标方法句柄的元数,L 是值数组的长度。
      ClassCastException - 如果参数与相应的绑定参数类型不匹配。
      参见:
    • dropArguments

      public static MethodHandle  dropArguments(MethodHandle  target, int pos, List <Class <?>> valueTypes)
      生成一个方法句柄,该句柄将在调用其他指定的参数之前丢弃一些伪参数目标方法句柄。新方法句柄的类型将与目标的类型相同,除了它还将在某个给定位置包括虚拟参数类型。

      pos 参数的范围可能介于零和N, 在哪里N是目标的元数。如果 pos 为零,则虚拟参数将在目标的实际参数之前;如果posN他们会来的。

      示例:

      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"));
       

      这个方法也等同于下面的代码:

       dropArguments (target, pos, valueTypes.toArray(new Class[0])) 
       
      参数:
      target - 删除参数后要调用的方法句柄
      pos - 要删除的第一个参数的位置(最左边为零)
      valueTypes - 要删除的参数的类型
      返回:
      在调用原始方法句柄之前删除给定类型的参数的方法句柄
      抛出:
      NullPointerException - 如果目标为空,或者如果 valueTypes 列表或其任何元素为空
      IllegalArgumentException - 如果 valueTypes 的任何元素是 void.class ,或者如果 pos 是负数或大于目标的元数,或者如果新方法句柄的类型有太多参数
    • dropArguments

      public static MethodHandle  dropArguments(MethodHandle  target, int pos, Class <?>... valueTypes)
      生成一个方法句柄,该句柄将在调用其他指定的参数之前丢弃一些伪参数目标方法句柄。新方法句柄的类型将与目标的类型相同,除了它还将在某个给定位置包括虚拟参数类型。

      pos 参数的范围可能介于零和N, 在哪里N是目标的元数。如果 pos 为零,则虚拟参数将在目标的实际参数之前;如果posN他们会来的。

      API 注意:
      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"));
       

      这个方法也等同于下面的代码:

       dropArguments (target, pos, Arrays.asList(valueTypes)) 
       
      参数:
      target - 删除参数后要调用的方法句柄
      pos - 要删除的第一个参数的位置(最左边为零)
      valueTypes - 要删除的参数的类型
      返回:
      在调用原始方法句柄之前删除给定类型的参数的方法句柄
      抛出:
      NullPointerException - 如果目标为空,或者如果 valueTypes 数组或其任何元素为空
      IllegalArgumentException - 如果 valueTypes 的任何元素是 void.class ,或者如果 pos 为负数或大于目标的元数,或者如果新方法句柄的类型为 太多的参数
    • dropArgumentsToMatch

      public static MethodHandle  dropArgumentsToMatch(MethodHandle  target, int skip, List <Class <?>> newTypes, int pos)
      调整目标方法句柄以匹配给定的参数类型列表。如有必要,添加伪参数。在匹配开始之前可以跳过一些前导参数。 target 的参数类型列表中的其余类型必须是起始位置 posnewTypes 类型列表的子列表。生成的句柄将具有目标句柄的参数类型列表,任何不匹配的参数类型(在匹配子列表之前或之后)插入目标原始参数的相应位置,就像 dropArguments(MethodHandle, int, Class[]) 一样。

      生成的句柄将具有与目标句柄相同的返回类型。

      用更正式的术语来说,假设这两个类型列表:

      • 目标句柄具有参数类型列表 S..., M...S 中的类型与 skip 指示的一样多。 M 类型应该与给定类型列表 newTypes 的一部分相匹配。
      • newTypes 列表包含类型 P..., M..., A...P 中的类型与 pos 指示的一样多。 M 类型正是目标句柄的参数类型列表中的 M 类型应该匹配的类型。 A 中的类型是在匹配子列表之后找到的附加类型。
      鉴于这些假设,调用 dropArgumentsToMatch 的结果将具有参数类型列表 S..., P..., M..., A... ,其中插入了 PA 类型,就像由 dropArguments(MethodHandle, int, Class[]) 插入的一样。
      API 注意:
      参数列表“有效相同”(即在公共前缀中相同)的两个方法句柄可以通过两次调用 dropArgumentsToMatch 相互转换为公共类型,如下所示:
      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 h1
      else
        h2 = dropArgumentsToMatch(h2, 0, h1.type().parameterList(), 0);  // lengthen h2
      MethodHandle h3 = guardWithTest(h0, h1, h2);
      assertEquals("xy", h3.invoke("x", "y", 1, "a", "b", "c"));
       
      参数:
      target - 适应的方法句柄
      skip - 要忽略的目标参数数量(它们将保持不变)
      newTypes - 与 target 的参数类型列表相匹配的类型列表
      pos - 放置在 newTypes 中,其中必须出现未跳过的目标参数
      返回:
      一个可能适应的方法句柄
      抛出:
      NullPointerException - 如果任一参数为空
      IllegalArgumentException - 如果 newTypes 的任何元素是 void.class ,或者如果 skip 为负数或大于目标的元数,或者如果 pos 为负数或大于 newTypes 列表大小,或者如果 newTypes 不包含 target 的未跳过pos 位置的参数类型。
      自从:
      9
    • dropReturn

      public static MethodHandle  dropReturn(MethodHandle  target)
      删除目标句柄的返回值(如果有)。返回的方法句柄将具有 void 返回类型。
      参数:
      target - 适应的方法句柄
      返回:
      一个可能适应的方法句柄
      抛出:
      NullPointerException - 如果 target 为空
      自从:
      16
    • filterArguments

      public static MethodHandle  filterArguments(MethodHandle  target, int pos, MethodHandle ... filters)
      通过预处理一个或多个参数来调整目标方法句柄,每个参数都有自己的一元过滤函数,然后调用目标,每个预处理参数替换为相应过滤函数的结果。

      预处理由一个或多个方法句柄执行,在 filters 数组的元素中指定。过滤器数组的第一个元素对应于目标的pos参数,依此类推。过滤器函数按从左到右的顺序调用。

      数组中的空参数被视为恒等函数,相应的参数保持不变。 (如果数组中没有非空元素,则返回原始目标。)每个过滤器都应用于适配器的相应参数。

      如果过滤器 F 适用于目标的 N th 参数,则 F 必须是一个只接受一个参数的方法句柄。 F 的唯一参数的类型替换了生成的适配方法句柄中目标的相应参数类型。 F 的返回类型必须与目标的相应参数类型相同。

      如果 filters 的元素(无论是否为 null)与目标中的参数位置不对应,则会出错。

      示例:

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

      这是生成的适配器的伪代码。在代码中,T 表示 target 和结果适配器的返回类型。 P /pB /b 分别表示过滤器位置 pos 之前和之后的参数和自变量的类型和值。 A[i] /a[i] 代表过滤后的参数和自变量的类型和值;它们还表示 filter[i] 句柄的返回类型。后者接受类型为 V[i] 的参数 v[i],这些参数也出现在生成的适配器的签名中。

      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: 结果适配器永远不是 变量方法句柄 ,即使原始目标方法句柄是。

      参数:
      target - 过滤参数后要调用的方法句柄
      pos - 要过滤的第一个参数的位置
      filters - 方法句柄最初调用过滤参数
      返回:
      包含指定参数过滤逻辑的方法句柄
      抛出:
      NullPointerException - 如果目标为空或 filters 数组为空
      IllegalArgumentException - 如果 filters 的非空元素与上述目标的相应参数类型不匹配,或者如果 pos+filters.length 大于 target.type().parameterCount() ,或者如果生成的方法句柄的类型为 太多的参数
    • collectArguments

      public static MethodHandle  collectArguments(MethodHandle  target, int pos, MethodHandle  filter)
      通过使用过滤器(另一个方法句柄)预处理其参数的子序列来调整目标方法句柄。预处理的参数被过滤器函数的结果(如果有的话)替换。然后在修改后的(通常是缩短的)参数列表上调用目标。

      如果过滤器返回一个值,则目标必须接受该值作为其位于 pos 位置的参数,之前和/或之后是任何未传递给过滤器的参数。如果过滤器返回 void,则目标必须接受所有未传递给过滤器的参数。没有参数被重新排序,并且从过滤器返回的结果替换(按顺序)最初传递给适配器的整个参数子序列。

      过滤器的参数类型(如果有)替换目标的零个或一个参数类型,在位置 pos ,在生成的适配方法句柄中。过滤器的返回类型(如果有)必须与位置 pos 的目标参数类型相同,并且该目标参数由过滤器的返回值提供。

      在所有情况下,pos 必须大于或等于零,并且 pos 也必须小于或等于目标的元数。

      示例:

      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"));
       

      这是生成的适配器的伪代码。在代码中,T 表示 target 和结果适配器的返回类型。 V /v 代表 filter 的返回类型和值,它们也分别在 target 的签名和参数中找到,除非 VvoidA /aC /c 表示target 签名中集合位置pos 前后的参数类型和值。它们还会出现在生成的适配器的签名和参数中,它们围绕着 B /b ,表示参数类型和 filter 的参数(如果有)。

      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...);
      }
       

      收集适配器 collectArguments(mh, 0, coll) 相当于首先“折叠”受影响的参数,然后在单独的步骤中删除它们,如下所示:

      mh = MethodHandles.dropArguments(mh, 1, coll.type().parameterList()); //step 2
      mh = MethodHandles.foldArguments(mh, coll); //step 1
       
      如果目标方法句柄除了过滤器 coll 的结果(如果有)之外不使用任何参数,则 collectArguments(mh, 0, coll) 等同于 filterReturnValue(coll, mh) 。如果过滤器方法句柄 coll 使用一个参数并产生非空结果,则 collectArguments(mh, N, coll) 等同于 filterArguments(mh, N, coll)。其他等价是可能的,但需要参数排列。

      Note: 结果适配器永远不是 变量方法句柄 ,即使原始目标方法句柄是。

      参数:
      target - 过滤参数子序列后要调用的方法句柄
      pos - 传递给过滤器的第一个适配器参数的位置,和/或接收过滤器结果的目标参数
      filter - 调用参数子序列的方法句柄
      返回:
      包含指定参数子序列过滤逻辑的方法句柄
      抛出:
      NullPointerException - 如果任一参数为空
      IllegalArgumentException - 如果 filter 的返回类型是非空的并且与目标的 pos 参数不同,或者如果 pos 不在 0 和目标的元数之间(含),或者如果生成的方法句柄的类型为 太多的参数
      参见:
    • filterReturnValue

      public static MethodHandle  filterReturnValue(MethodHandle  target, MethodHandle  filter)
      通过使用过滤器(另一个方法句柄)后处理其返回值(如果有)来调整目标方法句柄。过滤器的结果从适配器返回。

      如果目标返回一个值,则过滤器必须接受该值作为其唯一参数。如果目标返回 void,则过滤器不得接受任何参数。

      过滤器的返回类型替换了结果适配方法句柄中目标的返回类型。过滤器的参数类型(如果有)必须与目标的返回类型相同。

      示例:

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

      这是生成的适配器的伪代码。代码中,T /t代表target的结果类型和值; Vfilter 的结果类型;和 A /atarget 的参数和自变量的类型和值以及生成的适配器。

      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: 结果适配器永远不是 变量方法句柄 ,即使原始目标方法句柄是。

      参数:
      target - 在过滤返回值之前调用的方法句柄
      filter - 调用返回值的方法句柄
      返回:
      包含指定返回值过滤逻辑的方法句柄
      抛出:
      NullPointerException - 如果任一参数为空
      IllegalArgumentException - 如果 filter 的参数列表与上述目标的返回类型不匹配
    • foldArguments

      public static MethodHandle  foldArguments(MethodHandle  target, MethodHandle  combiner)
      通过预处理它的一些参数来调整目标方法句柄,然后使用预处理的结果调用目标,将其插入到原始参数序列中。

      预处理由第二个方法句柄 combiner 执行。在传递给适配器的参数中,第一个 N 个参数被复制到组合器,然后调用组合器。 (这里,N 被定义为组合器的参数计数。)在此之后,控制传递给目标,组合器的任何结果都插入到原始 N 传入参数之前。

      如果组合器返回一个值,则目标的第一个参数类型必须与组合器的返回类型相同,并且目标的下一个N参数类型必须与组合器的参数完全匹配。

      如果组合器返回 void,则不会插入任何结果,并且目标的第一个N参数类型必须与组合器的参数完全匹配。

      生成的适配器与目标的类型相同,除了第一个参数类型被删除,如果它对应于组合器的结果。

      (请注意,dropArguments 可用于删除组合器或目标不希望接收的任何参数。如果某些传入参数仅用于组合器,请考虑使用 asCollector ,因为这些参数不需要在进入目标时住在堆栈上。)

      示例:

      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"));
       

      这是生成的适配器的伪代码。在代码中,T 表示 target 和结果适配器的结果类型。 V /v表示折叠位置之前的target的形参和自变量的类型和值; V 也是 combiner 的结果类型。 A /a 表示折叠位置的N 参数和参数的类型和值。 B /b 表示折叠参数和参数后面的target 参数和参数的类型和值。

      // 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: 结果适配器永远不是 变量方法句柄 ,即使原始目标方法句柄是。

      参数:
      target - 组合参数后要调用的方法句柄
      combiner - 最初调用传入参数的方法句柄
      返回:
      包含指定参数折叠逻辑的方法句柄
      抛出:
      NullPointerException - 如果任一参数为空
      IllegalArgumentException - 如果 combiner 的返回类型为非空且与目标的第一个参数类型不同,或者如果目标的初始 N 参数类型(跳过与 combiner 的返回类型匹配的)与combiner 的参数类型
    • foldArguments

      public static MethodHandle  foldArguments(MethodHandle  target, int pos, MethodHandle  combiner)
      通过预处理它的一些参数来调整目标方法句柄,从给定位置开始,然后使用预处理的结果调用目标,插入到折叠参数之前的原始参数序列中。

      此方法与 foldArguments(MethodHandle, MethodHandle) 密切相关,但允许控制折叠发生在参数列表中的位置。控制它的参数 pos 是一个从零开始的索引。上述方法 foldArguments(MethodHandle, MethodHandle) 假定位置 0。

      API 注意:
      示例:
        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"));
       

      这是生成的适配器的伪代码。在代码中,T 表示 target 和结果适配器的结果类型。 V /v表示折叠位置之前的target的形参和自变量的类型和值; V 也是 combiner 的结果类型。 A /a 表示折叠位置的N 参数和参数的类型和值。 Z /zB /b 分别表示以 pos 开始的折叠参数和参数之前和之后的 target 参数和参数的类型和值。

      // 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: 结果适配器永远不是 变量方法句柄 ,即使原始目标方法句柄是。

      参数:
      target - 组合参数后要调用的方法句柄
      pos - 开始折叠和插入折叠结果的位置;如果这是 0 ,效果与 foldArguments(MethodHandle, MethodHandle) 相同。
      combiner - 最初调用传入参数的方法句柄
      返回:
      包含指定参数折叠逻辑的方法句柄
      抛出:
      NullPointerException - 如果任一参数为空
      IllegalArgumentException - 如果满足以下两个条件之一: (1) combiner 的返回类型是非void 并且与目标签名的位置pos 处的参数类型不同; (2) 目标签名位置pos处的N参数类型(跳过与combiner的返回类型匹配的一个)与combiner的参数类型不同。
      自从:
      9
      参见:
    • guardWithTest

      public static MethodHandle  guardWithTest(MethodHandle  test, MethodHandle  target, MethodHandle  fallback)
      通过用测试保护它来创建一个适应目标方法句柄的方法句柄,一个boolean方法句柄。如果守卫失败,则会调用回退句柄。所有三个方法句柄必须具有相同的对应参数和返回类型,除了测试的返回类型必须是boolean,并且测试允许比其他两个方法句柄具有更少的参数。

      这是生成的适配器的伪代码。代码中T表示涉及的三个句柄的结果类型统一; A /atarget 参数的类型和值以及 test 消耗的参数;和 B /btarget 参数和参数的那些类型和值不被 test 使用。

      boolean test(A...);
      T target(A...,B...);
      T fallback(A...,B...);
      T adapter(A... a,B... b) {
       if (test(a...))
        return target(a..., b...);
       else
        return fallback(a..., b...);
      }
       
      请注意,测试参数(伪代码中的a...)无法通过测试的执行进行修改,因此会按原样从调用者传递到目标或适当回退。
      参数:
      test - 用于测试的方法句柄,必须返回boolean
      target - 测试通过时调用的方法句柄
      fallback - 测试失败时调用的方法句柄
      返回:
      包含指定的 if/then/else 逻辑的方法句柄
      抛出:
      NullPointerException - 如果任何参数为空
      IllegalArgumentException - 如果 test 不返回boolean,或者所有三种方法类型都不匹配(test 的返回类型更改为与目标的返回类型匹配)。
    • catchException

      public static MethodHandle  catchException(MethodHandle  target, Class <? extends Throwable > exType, MethodHandle  handler)
      通过在异常处理程序中运行它来创建一个适应目标方法句柄的方法句柄。如果目标正常返回,则适配器返回该值。如果抛出与指定类型匹配的异常,则调用回退句柄而不是异常,加上原始参数。

      目标和处理程序必须具有相同的相应参数和返回类型,但处理程序可以省略尾随参数(类似于 guardWithTest 中的谓词)。此外,处理程序必须有一个额外的前导参数 exType 或超类型。

      这是生成的适配器的伪代码。在代码中,T 代表 targethandler 的返回类型,对应的是结果适配器的返回类型; A /ahandler 使用的结果句柄的参数类型和值;和 B /b ,那些被 handler 丢弃的结果句柄的参数。

      T target(A..., B...);
      T handler(ExType, A...);
      T adapter(A... a, B... b) {
       try {
        return target(a..., b...);
       } catch (ExType ex) {
        return handler(ex, a...);
       }
      }
       
      请注意,保存的参数(伪代码中的a...)无法通过目标的执行进行修改,因此如果调用处理程序,则将原样从调用方传递到处理程序。

      目标和处理程序必须返回相同的类型,即使处理程序总是抛出异常。 (这可能会发生,例如,因为处理程序正在模拟 finally 子句)。要创建这样的抛出处理程序,请使用 throwException 组合处理程序创建逻辑,以便创建正确返回类型的方法句柄。

      参数:
      target - 要调用的方法句柄
      exType - 处理程序将捕获的异常类型
      handler - 抛出匹配异常时调用的方法句柄
      返回:
      包含指定 try/catch 逻辑的方法句柄
      抛出:
      NullPointerException - 如果任何参数为空
      IllegalArgumentException - 如果 handler 不接受给定的异常类型,或者如果方法句柄类型在它们的返回类型和它们相应的参数中不匹配
      参见:
    • throwException

      public static MethodHandle  throwException(Class <?> returnType, Class <? extends Throwable > exType)
      生成一个方法句柄,它将抛出给定 exType 的异常。方法句柄将接受 exType 的单个参数,并立即将其作为异常抛出。方法类型将名义上指定返回 returnType 。返回类型可以是任何方便的类型:这对方法句柄的行为无关紧要,因为它永远不会正常返回。
      参数:
      returnType - 所需方法句柄的返回类型
      exType - 所需方法句柄的参数类型
      返回:
      可以抛出给定异常的方法句柄
      抛出:
      NullPointerException - 如果任一参数为空
    • loop

      public static MethodHandle  loop(MethodHandle []... clauses)
      构造一个表示循环的方法句柄,其中包含多个循环变量,这些循环变量在每次迭代时更新和检查。由于其中一个谓词而导致循环终止时,将运行相应的终结器并传递循环的结果,即结果句柄的返回值。

      直观地说,每个循环都由一个或多个“子句”组成,每个子句指定一个本地 iteration variable 和/或一个循环出口。循环的每次迭代按顺序执行每个子句。一个子句可以选择更新它的迭代变量;它还可以选择执行测试和条件循环退出。为了用方法句柄来表达这个逻辑,每个子句将指定最多四个独立的动作:

      • init: 在循环执行之前,初始化一个V 类型的迭代变量v
      • step: 当子句执行时,迭代变量 v 的更新步骤。
      • pred: 当一个子句执行时,一个谓词执行以测试 for 循环退出。
      • fini: 如果子句导致循环退出,则终结器执行以计算循环的返回值。
      所有迭代变量类型的完整序列,按子句顺序,将被标记为 (V...) 。值本身将是 (v...) 。当我们谈到“参数列表”时,我们通常指的是类型,但在某些上下文中(描述执行)列表将是实际值。

      根据某些规则,这些子句部分中的一些可能会被省略,并且在这种情况下提供了有用的默认行为。有关详细说明,请参见下文。

      Parameters optional everywhere: 允许但不要求每个子句函数接受每个迭代变量的参数 v。作为例外,init 函数不能采用任何v 参数,因为在执行 init 函数时尚未计算这些值。任何子句函数都可能忽略采用它有权采用的参数的任何尾随子序列。事实上,任何子句函数都可能根本不带任何参数。

      Loop parameters: 子句函数可以采用它有权使用的所有迭代变量值,在这种情况下,它还可以采用更多尾随参数。此类额外值称为 loop parameters ,其类型和值标记为 (A...)(a...) 。这些成为生成的循环句柄的参数,在执行循环时提供。 (由于初始化函数不接受迭代变量 v ,初始化函数的任何参数自动成为循环参数 a 。)与迭代变量一样,允许但不要求子句函数接受循环参数。这些循环参数充当在整个循环中可见的循环不变值。

      Parameters visible everywhere: 每个非 init 子句函数都被允许观察整个循环状态,因为它可以传递当前迭代变量值和传入循环参数的完整列表 (v... a...)。 init 函数可以以 (a...) 的形式观察初始循环前状态。大多数子句函数不需要所有这些信息,但它们将像 dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>) 一样正式连接到它。 更具体地说,我们将使用符号 (V*) 来表示完整序列 (V...) 的任意前缀(对于 (v*)(A*)(a*) 也是如此)。在该表示法中,init 函数参数列表的一般形式是 (A*) ,非 init 函数参数列表的一般形式是 (V*)(V... A*)

      Checking clause structure: 给定一组子句,执行许多检查和调整以连接循环的所有部分。它们在下面的步骤中有详细说明。在这些步骤中,“必须”一词的每次出现都对应于一个地方,如果循环组合器的输入不满足所需的约束条件,将抛出 IllegalArgumentException

      Effectively identical sequences: 参数列表 A 被定义为另一个参数列表 B effectively identical 如果 AB 相同,或者如果 A 更短并且与适当的前缀 B 相同。当谈到一组无序的参数列表时,如果该集合包含最长列表,并且该集合的所有成员都与该最长列表有效相同,则我们说该集合作为一个整体“有效相同”。例如,(V*) 形式的任何一组类型序列实际上是相同的,如果添加更多 (V... A*) 形式的序列,情况也是如此。

      Step 0: Determine clause structure.

      1. 子句数组(MethodHandle[][] 类型)必须是非null 且至少包含一个元素。
      2. 子句数组不能包含 null 或长度超过四个元素的子数组。
      3. 短于四个元素的子句被视为好像它们被 null 个元素填充到长度为四。通过将元素附加到数组来进行填充。
      4. 包含所有 null 的子句将被忽略。
      5. 每个子句都被视为一个四元组函数,称为“init”、“step”、“pred”和“fini”。

      Step 1A: Determine iteration variable types (V...) .

      1. 每个子句的迭代变量类型是使用子句的 init 和 step 返回类型确定的。
      2. 如果两个函数都被省略,则对应的子句没有迭代变量(void 用作指示该类型的类型)。如果省略其中一个,则另一个的返回类型定义子句的迭代变量类型。如果两者都给出,则公共返回类型(它们必须相同)定义子句的迭代变量类型。
      3. 形成返回类型列表(按子句顺序),省略所有出现的 void
      4. 此类型列表称为“迭代变量类型”((V...))。

      Step 1B: Determine loop parameters (A...) .

      • 检查并收集 init 函数参数列表(其形式为 (A*))。
      • 在移除迭代变量类型后,检查并收集 step、pred 和 fini 参数列表的后缀。 (它们必须具有 (V... A*) 的形式;仅收集 (A*) 部分。)
      • 不要从不以所有迭代变量类型开头的 step、pred 和 fini 参数列表中收集后缀。 (将在步骤 2 中检查这些类型以及所有子句函数类型。)
      • 省略的子句函数将被忽略。 (等效地,它们被视为具有空参数列表。)
      • 所有收集的参数列表必须有效地相同。
      • 最长的参数列表(必须是唯一的)称为“外部参数列表”((A...))。
      • 如果没有这样的参数列表,则将外部参数列表视为空序列。
      • 由迭代变量类型和后跟外部参数类型组成的组合列表称为“内部参数列表”。

      Step 1C: Determine loop return type.

      1. 检查 fini 函数返回类型,忽略省略的 fini 函数。
      2. 如果没有 fini 函数,则循环返回类型为 void
      3. 否则,fini 函数的公共返回类型R(它们的返回类型必须相同)定义循环返回类型。

      Step 1D: Check other types.

      1. 必须至少有一个非省略的 pred 函数。
      2. 每个未省略的 pred 函数都必须有一个 boolean 返回类型。

      Step 2: Determine parameter lists.

      1. 生成的循环句柄的参数列表将是外部参数列表 (A...)
      2. 初始化函数的参数列表将调整为外部参数列表。 (请注意,它们的参数列表实际上已经与该列表相同。)
      3. 每个非省略、非初始化(step、pred 和 fini)函数的参数列表必须与内部参数列表 (V... A...) 有效地相同。

      Step 3: Fill in omitted functions.

      1. 如果省略了 init 函数,则使用 默认值 作为子句的迭代变量类型。
      2. 如果省略了阶跃函数,则使用子句迭代变量类型的恒等函数;在前面子句的非void迭代变量的身份函数参数之前插入丢弃的参数参数。 (这会将循环变量变成局部循环不变量。)
      3. 如果省略 pred 函数,则使用常量 true 函数。 (就此子句而言,这将使循环继续进行。请注意,在这种情况下,无法访问相应的 fini 函数。)
      4. 如果省略 fini 函数,则使用 默认值 作为循环返回类型。

      Step 4: Fill in missing parameter types.

      1. 此时,每个 init 函数参数列表实际上与外部参数列表 (A...) 相同,但有些列表可能更短。对于每个带有短参数列表的 init 函数,填充列表的末尾。
      2. 此时,每个非 init 函数参数列表实际上与内部参数列表 (V... A...) 相同,但有些列表可能更短。对于每个具有短参数列表的非初始化函数,填充列表的末尾。
      3. 参数列表由 删除未使用的尾随参数 填充。

      Final observations.

      1. 在这些步骤之后,所有子句都通过提供省略的函数和参数进行了调整。
      2. 所有 init 函数都有一个公共参数类型列表 (A...) ,最终循环句柄也将具有该列表。
      3. 所有 fini 函数都有一个共同的返回类型 R ,最终循环句柄也将有。
      4. 所有非初始化函数都有一个公共参数类型列表 (V... A...) ,其中包含(非void )迭代变量 V 后跟循环参数。
      5. 每对 init 和 step 函数的返回类型都一致 V
      6. 每个非初始化函数将能够观察所有迭代变量的当前值(v...)
      7. 每个函数都将能够观察所有循环参数的传入值(a...)

      Example. 作为上述步骤 1A 的结果,loop 组合器具有以下属性:

      • 给定 N 子句 Cn = {null, Sn, Pn}n = 1..N
      • 假设谓词句柄 Pnnull 或没有参数。 (只有一个 Pn 必须是非 null 。)
      • 假设步骤句柄 Sn 具有签名 (B1..BX)Rn,对于某些常量 X>=N
      • 假设 Q 是非空类型 Rn 的计数,而 (V1...VQ) 是这些类型的序列。
      • n = 1..min(X,Q) 必须是 Vn == Bn
      • 参数类型 Vn 将被解释为循环局部状态元素 (V...)
      • 任何剩余类型 BQ+1..BX(如果是 Q<X)将确定生成的循环句柄的参数类型 (A...)
      在此示例中,循环句柄参数 (A...) 派生自步骤函数,如果大部分循环计算发生在步骤中,这是很自然的。对于某些循环,计算负担可能在 pred 函数中最重,因此 pred 函数可能需要接受循环参数值。对于具有复杂退出逻辑的循环,fini 函数可能需要接受循环参数,同样对于具有复杂入口逻辑的循环,init 函数将需要额外的参数。出于这些原因,确定这些参数的规则在所有子句部分中尽可能对称。通常,循环参数在整个循环中充当公共不变值,而迭代变量充当公共变量值,或者(如果没有阶梯函数)作为内部循环不变量临时值。

      Loop execution.

      1. 调用循环时,循环输入值保存在局部变量中,以传递给每个子句函数。这些局部变量是循环不变的。
      2. 每个 init 函数都按子句顺序执行(传递外部参数 (a...) )并将非 void 值保存(作为迭代变量 (v...) )到局部变量中。这些局部变量将循环变化(除非它们的步骤表现为恒等函数,如上所述)。
      3. 所有函数执行(初始化函数除外)都将传递内部参数列表,包括非void迭代值(v...)(按子句顺序)然后循环输入(a...)(按参数顺序)。
      4. 然后按子句顺序(pred 之前的步骤)执行 step 和 pred 函数,直到 pred 函数返回 false
      5. 步进函数调用的非void结果用于更新循环变量序列(v...)中的相应值。更新后的值对所有后续函数调用立即可见。
      6. 如果 pred 函数返回 false ,则调用相应的 fini 函数,并将结果值(类型 R )作为一个整体从循环中返回。
      7. 如果所有 pred 函数始终返回 true,则不会调用任何 fini 函数,并且除非抛出异常,否则循环无法退出。

      Usage tips.

      • 虽然每个步进函数都会接收all循环变量的当前值,但有时一个步进函数只需要观察其自身变量的当前值。在这种情况下,阶跃函数可能需要显式 删除所有前面的循环变量 。这将需要在类似 dropArguments(step, 0, V0.class, ...) 的表达式中提及它们的类型。
      • 循环变量不需要改变;它们可以是循环不变的。子句可以通过合适的 init 函数创建循环不变性,而没有 step、pred 或 fini 函数。这可能有助于将传入的循环参数“连接”到相邻循环变量的 step 或 pred 函数中。
      • 如果某些子句函数是实例上的虚方法,则可以使用诸如 new MethodHandle[]{identity(ObjType.class)} 之类的初始子句将实例本身方便地放置在初始不变循环“变量”中。在那种情况下,实例引用将是第一个迭代变量值,并且将虚方法用作子句部分将很容易,因为它们都将采用与该值匹配的前导实例引用。

      这是生成的循环句柄的伪代码。如上,Vv代表循环变量的类型和取值; Aa 表示传递给整个循环的参数; R 是所有终结器以及结果循环的通用结果类型。

      V... init...(A...);
      boolean pred...(V..., A...);
      V... step...(V..., A...);
      R fini...(V..., A...);
      R loop(A... a) {
       V... v... = init...(a...);
       for (;;) {
        for ((v, p, s, f) in (v..., pred..., step..., fini...)) {
         v = s(v..., a...);
         if (!p(v..., a...)) {
          return f(v..., a...);
         }
        }
       }
      }
       
      请注意,参数类型列表 (V...)(A...) 已扩展到它们的完整长度,即使个别子句函数可能会忽略全部。如上所述,缺少的参数由 dropArgumentsToMatch(MethodHandle, int, List, int) 填充。
      API 注意:
      示例:
      // iterative implementation of the factorial function as a loop handle
      static int one(int k) { return 1; }
      static int inc(int i, int acc, int k) { return i + 1; }
      static int mult(int i, int acc, int k) { return i * acc; }
      static boolean pred(int i, int acc, int k) { return i < k; }
      static int fin(int i, int acc, int k) { return acc; }
      // assume MH_one, MH_inc, MH_mult, MH_pred, and MH_fin are handles to the above methods
      // null initializer for counter, should initialize to 0
      MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};
      MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};
      MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);
      assertEquals(120, loop.invoke(5));
       
      同样的示例,删除参数并使用组合器:
      // simplified implementation of the factorial function as a loop handle
      static int inc(int i) { return i + 1; } // drop acc, k
      static int mult(int i, int acc) { return i * acc; } //drop k
      static 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 0
      MethodHandle MH_one = MethodHandles.constant(int.class, 1);
      MethodHandle MH_pred = MethodHandles.dropArguments(MH_cmp, 1, int.class); // drop acc
      MethodHandle MH_fin = MethodHandles.dropArguments(MethodHandles.identity(int.class), 0, int.class); // drop i
      MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};
      MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};
      MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);
      assertEquals(720, loop.invoke(6));
       
      一个类似的示例,使用一个辅助对象来保存一个循环参数:
      // instance-based implementation of the factorial function as a loop handle
      static 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 0
      MethodHandle 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));
       
      参数:
      clauses - 遵守上述规则的 MethodHandle 的数组(4 元组)数组。
      返回:
      体现由参数定义的循环行为的方法句柄。
      抛出:
      IllegalArgumentException - 以防违反上述任何约束。
      自从:
      9
      参见:
    • whileLoop

      public static MethodHandle  whileLoop(MethodHandle  init, MethodHandle  pred, MethodHandle  body)
      从初始值设定项、主体和谓词构造一个 while 循环。这是 通用循环组合器 的便利包装器。

      pred句柄描述了循环条件;和 body ,它的主体。此方法产生的循环将在每次迭代中首先评估谓词,然后执行其主体(如果谓词的计算结果为 true )。一旦谓词的计算结果为 false,循环就会终止(在这种情况下不会执行主体)。

      init 句柄描述了一个附加的可选循环局部变量的初始值。在每次迭代中,此循环局部变量(如果存在)将传递给 body 并使用从其调用返回的值进行更新。循环执行的结果将是附加循环局部变量(如果存在)的最终值。

      以下规则适用于这些参数句柄:

      • body 句柄不能是 null ;它的类型必须是 (V A...)V 形式,其中 V 是非 void ,否则是 (A...)void 。 (在 void 的情况下,我们将类型 void 分配给名称 V ,我们将编写 (V A...)V 并理解 void 类型 V 从参数列表中悄悄删除,留下 (A...)V 。)
      • 主体的参数列表 (V A...) 称为 internal parameter list 。它将约束其他循环部分的参数列表。
      • 如果从内部参数列表中删除迭代变量类型 V,则生成的较短列表 (A...) 称为 external parameter list
      • 主体返回类型 V ,如果非 void ,则确定循环的附加状态变量的类型。正文必须接受并返回这种类型的值 V
      • 如果 init 是非 null ,它必须有返回类型 V 。它的参数列表(一些 表格(A*) )必须是 有效相同 到外部参数列表 (A...)
      • 如果 initnull ,循环变量将被初始化为其 默认值
      • pred 句柄不能是 null。它的返回类型必须是 boolean。它的参数列表(为空或形式为 (V A*) )必须与内部参数列表有效地相同。

      生成的循环句柄的结果类型和参数签名确定如下:

      • 循环句柄的结果类型是主体的结果类型V
      • 循环句柄的参数类型是外部参数列表中的 (A...) 类型。

      这是生成的循环句柄的伪代码。代码中,V /v代表唯一循环变量的类型/值,以及循环的结果类型;和 A /a ,传递给循环的参数。

      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 注意:
      示例:
      // implement the zip function for lists as a loop handle
      static List<String> initZip(Iterator<String> a, Iterator<String> b) { return new ArrayList<>(); }
      static boolean zipPred(List<String> zip, Iterator<String> a, Iterator<String> b) { return a.hasNext() && b.hasNext(); }
      static List<String> zipStep(List<String> zip, Iterator<String> a, Iterator<String> b) {
       zip.add(a.next());
       zip.add(b.next());
       return zip;
      }
      // assume MH_initZip, MH_zipPred, and MH_zipStep are handles to the above methods
      MethodHandle loop = MethodHandles.whileLoop(MH_initZip, MH_zipPred, MH_zipStep);
      List<String> a = Arrays.asList("a", "b", "c", "d");
      List<String> b = Arrays.asList("e", "f", "g", "h");
      List<String> zipped = Arrays.asList("a", "e", "b", "f", "c", "g", "d", "h");
      assertEquals(zipped, (List<String>) loop.invoke(a.iterator(), b.iterator()));
       
      , 该方法的实现可以表示如下:
      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);
      }
       
      参数:
      init - 可选的初始化器,提供循环变量的初始值。可能是 null ,表示默认初始值。有关其他限制,请参见上文。
      pred - 循环条件,可能不是 null 。它的结果类型必须是 boolean 。有关其他限制,请参见上文。
      body - 循环体,可能不是 null 。它控制循环参数和结果类型。有关其他限制,请参见上文。
      返回:
      一个方法句柄,实现参数所描述的 while 循环。
      抛出:
      IllegalArgumentException - 如果违反参数规则。
      NullPointerException - 如果 predbodynull
      自从:
      9
      参见:
    • doWhileLoop

      public static MethodHandle  doWhileLoop(MethodHandle  init, MethodHandle  body, MethodHandle  pred)
      从初始值设定项、主体和谓词构造一个 do-while 循环。这是 通用循环组合器 的便利包装器。

      pred句柄描述了循环条件;和 body ,它的主体。此方法产生的循环将在每次迭代中首先执行其主体,然后评估谓词。一旦执行主体后谓词的计算结果为 false,循环将终止。

      init 句柄描述了一个附加的可选循环局部变量的初始值。在每次迭代中,此循环局部变量(如果存在)将传递给 body 并使用从其调用返回的值进行更新。循环执行的结果将是附加循环局部变量(如果存在)的最终值。

      以下规则适用于这些参数句柄:

      • body 句柄不能是 null ;它的类型必须是 (V A...)V 形式,其中 V 是非 void ,否则是 (A...)void 。 (在 void 的情况下,我们将类型 void 分配给名称 V ,我们将编写 (V A...)V 并理解 void 类型 V 从参数列表中悄悄删除,留下 (A...)V 。)
      • 主体的参数列表 (V A...) 称为 internal parameter list 。它将约束其他循环部分的参数列表。
      • 如果从内部参数列表中删除迭代变量类型 V,则生成的较短列表 (A...) 称为 external parameter list
      • 主体返回类型 V ,如果非 void ,则确定循环的附加状态变量的类型。正文必须接受并返回这种类型的值 V
      • 如果 init 是非 null ,它必须有返回类型 V 。它的参数列表(一些 表格(A*) )必须是 有效相同 到外部参数列表 (A...)
      • 如果 initnull ,循环变量将被初始化为其 默认值
      • pred 句柄不能是 null。它的返回类型必须是 boolean。它的参数列表(为空或形式为 (V A*) )必须与内部参数列表有效地相同。

      生成的循环句柄的结果类型和参数签名确定如下:

      • 循环句柄的结果类型是主体的结果类型V
      • 循环句柄的参数类型是外部参数列表中的 (A...) 类型。

      这是生成的循环句柄的伪代码。代码中,V /v代表唯一循环变量的类型/值,以及循环的结果类型;和 A /a ,传递给循环的参数。

      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 注意:
      示例:
      // int i = 0; while (i < limit) { ++i; } return i; => limit
      static int zero(int limit) { return 0; }
      static int step(int i, int limit) { return i + 1; }
      static boolean pred(int i, int limit) { return i < limit; }
      // assume MH_zero, MH_step, and MH_pred are handles to the above methods
      MethodHandle loop = MethodHandles.doWhileLoop(MH_zero, MH_step, MH_pred);
      assertEquals(23, loop.invoke(23));
       
      , 该方法的实现可以表示如下:
      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);
      }
       
      参数:
      init - 可选的初始化器,提供循环变量的初始值。可能是 null ,表示默认初始值。有关其他限制,请参见上文。
      body - 循环体,可能不是 null 。它控制循环参数和结果类型。有关其他限制,请参见上文。
      pred - 循环条件,可能不是 null 。它的结果类型必须是 boolean 。有关其他限制,请参见上文。
      返回:
      一个方法句柄,实现参数所描述的 while 循环。
      抛出:
      IllegalArgumentException - 如果违反参数规则。
      NullPointerException - 如果 predbodynull
      自从:
      9
      参见:
    • countedLoop

      public static MethodHandle  countedLoop(MethodHandle  iterations, MethodHandle  init, MethodHandle  body)
      构造一个运行给定迭代次数的循环。这是 通用循环组合器 的便利包装器。

      迭代次数由iterations句柄评估结果决定。循环计数器 i 是类型为 int 的额外循环迭代变量。它将被初始化为 0 并在每次迭代中递增 1。

      如果 body 句柄返回非 void 类型 V ,则还存在该类型的前导循环迭代变量。此变量使用可选的 init 句柄初始化,或者如果句柄为 null 则初始化为 V 类型的 默认值

      在每次迭代中,迭代变量都传递给 body 句柄的调用。从正文(类型为 V )返回的非 void 值更新前导迭代变量。循环句柄执行的结果将是该变量的最终 V 值(如果没有 V 变量,则为 void )。

      以下规则适用于参数句柄:

      • iterations 句柄不能是 null,并且必须返回类型 int,此处在参数类型列表中称为 I
      • body 句柄不能是 null ;它的类型必须是 (V I A...)V 形式,其中 V 是非 void ,否则是 (I A...)void 。 (在 void 的情况下,我们将类型 void 分配给名称 V ,我们将编写 (V I A...)V 并理解 void 类型 V 从参数列表中悄悄删除,留下 (I A...)V 。)
      • 主体的参数列表 (V I A...) 有助于称为 internal parameter list 的类型列表。它将约束其他循环部分的参数列表。
      • 作为一种特殊情况,如果主体仅提供 VI 类型,而没有额外的 A 类型,则内部参数列表由 iterations 句柄的参数类型 A... 扩展。
      • 如果从内部参数列表中删除迭代变量类型 (V I),则生成的较短列表 (A...) 称为 external parameter list
      • 主体返回类型 V ,如果非 void ,则确定循环的附加状态变量的类型。主体必须既接受前导参数又返回此类型的值 V
      • 如果 init 是非 null ,它必须有返回类型 V 。它的参数列表(一些 form (A*) )必须是 有效相同 到外部参数列表 (A...)
      • 如果 initnull ,循环变量将被初始化为其 默认值
      • iterations 的参数列表(某种形式 (A*) )必须与外部参数列表 (A...) 有效相同。

      生成的循环句柄的结果类型和参数签名确定如下:

      • 循环句柄的结果类型是主体的结果类型V
      • 循环句柄的参数类型是外部参数列表中的 (A...) 类型。

      这是生成的循环句柄的伪代码。代码中,V /v代表第二个循环变量的类型/值以及循环的结果类型;和 A... /a... 表示传递给循环的参数。

      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 注意:
      具有完全一致的主体方法的示例:
      // String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;
      // => a variation on a well known theme
      static String step(String v, int counter, String init) { return "na " + v; }
      // assume MH_step is a handle to the method above
      MethodHandle 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!"));
       
      ,具有最简单的主体方法类型的示例,并将迭代次数传递给循环调用:
      // String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;
      // => a variation on a well known theme
      static String step(String v, int counter ) { return "na " + v; }
      // assume MH_step is a handle to the method above
      MethodHandle 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 " + v
      assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke(13, "Lambdaman!"));
       
      , 将迭代次数、要附加到的字符串和要附加的字符串视为循环参数的示例:
      // String s = "Lambdaman!", t = "na"; for (int i = 0; i < 13; ++i) { s = t + " " + s; } return s;
      // => a variation on a well known theme
      static String step(String v, int counter, int iterations_, String pre, String start_) { return pre + " " + v; }
      // assume MH_step is a handle to the method above
      MethodHandle 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 + " " + v
      assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke(13, "na", "Lambdaman!"));
       
      , 说明 dropArgumentsToMatch(MethodHandle, int, List, int) 强制执行循环类型用法的示例:
      // String s = "Lambdaman!", t = "na"; for (int i = 0; i < 13; ++i) { s = t + " " + s; } return s;
      // => a variation on a well known theme
      static String step(String v, int counter, String pre) { return pre + " " + v; }
      // assume MH_step is a handle to the method above
      MethodType 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 + " " + v
      assertEquals("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);
      }
       
      参数:
      iterations - 一个非 null 句柄,用于返回此循环应运行的迭代次数。句柄的结果类型必须是 int 。有关其他限制,请参见上文。
      init - 可选的初始化器,提供循环变量的初始值。可能是 null ,表示默认初始值。有关其他限制,请参见上文。
      body - 循环体,可能不是 null 。它控制标准情况下的循环参数和结果类型(详见上文)。它必须接受自己的返回类型(如果非空)加上一个 int 参数(用于计数器),并且可以接受任意数量的附加类型。有关其他限制,请参见上文。
      返回:
      表示循环的方法句柄。
      抛出:
      NullPointerException - 如果 iterationsbody 句柄是 null
      IllegalArgumentException - 如果任何参数违反了上面制定的规则。
      自从:
      9
      参见:
    • countedLoop

      public static MethodHandle  countedLoop(MethodHandle  start, MethodHandle  end, MethodHandle  init, MethodHandle  body)
      构造一个对一定范围内的数字进行计数的循环。这是 通用循环组合器 的便利包装器。

      循环计数器 i 是类型为 int 的循环迭代变量。 startend 句柄确定循环计数器的开始(包括)和结束(不包括)值。循环计数器将初始化为从start句柄的计算返回的int值,并运行到从end返回的值(独占),步长为1。

      如果 body 句柄返回非 void 类型 V ,则还存在该类型的前导循环迭代变量。此变量使用可选的 init 句柄初始化,或者如果句柄为 null 则初始化为 V 类型的 默认值

      在每次迭代中,迭代变量都传递给 body 句柄的调用。从正文(类型为 V )返回的非 void 值更新前导迭代变量。循环句柄执行的结果将是该变量的最终 V 值(如果没有 V 变量,则为 void )。

      以下规则适用于参数句柄:

      • startend 句柄不能是 null ,并且都必须返回通用类型 int ,此处在参数类型列表中称为 I
      • body 句柄不能是 null ;它的类型必须是 (V I A...)V 形式,其中 V 是非 void ,否则是 (I A...)void 。 (在 void 的情况下,我们将类型 void 分配给名称 V ,我们将编写 (V I A...)V 并理解 void 类型 V 从参数列表中悄悄删除,留下 (I A...)V 。)
      • 主体的参数列表 (V I A...) 有助于称为 internal parameter list 的类型列表。它将约束其他循环部分的参数列表。
      • 作为一种特殊情况,如果主体仅提供 VI 类型,而没有额外的 A 类型,则内部参数列表由 end 句柄的参数类型 A... 扩展。
      • 如果从内部参数列表中删除迭代变量类型 (V I),则生成的较短列表 (A...) 称为 external parameter list
      • 主体返回类型 V ,如果非 void ,则确定循环的附加状态变量的类型。主体必须既接受前导参数又返回此类型的值 V
      • 如果 init 是非 null ,它必须有返回类型 V 。它的参数列表(一些 form (A*) )必须是 有效相同 到外部参数列表 (A...)
      • 如果 initnull ,循环变量将被初始化为其 默认值
      • start 的参数列表(某种形式 (A*) )必须与外部参数列表 (A...) 有效相同。
      • 同样,end 的参数列表必须与外部参数列表有效地相同。

      生成的循环句柄的结果类型和参数签名确定如下:

      • 循环句柄的结果类型是主体的结果类型V
      • 循环句柄的参数类型是外部参数列表中的 (A...) 类型。

      这是生成的循环句柄的伪代码。代码中,V /v代表第二个循环变量的类型/值以及循环的结果类型;和 A... /a... 表示传递给循环的参数。

      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 注意:
      该方法的实现可以表示如下:
      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);
      }
       
      参数:
      start - 一个非 null 句柄,用于返回循环计数器的起始值,它必须是 int 。有关其他限制,请参见上文。
      end - 一个非 null 句柄,用于返回循环计数器的结束值(循环将运行到 end-1 )。结果类型必须是 int 。有关其他限制,请参见上文。
      init - 可选的初始化器,提供循环变量的初始值。可能是 null ,表示默认初始值。有关其他限制,请参见上文。
      body - 循环体,可能不是 null 。它控制标准情况下的循环参数和结果类型(详见上文)。它必须接受自己的返回类型(如果非空)加上一个 int 参数(用于计数器),并且可以接受任意数量的附加类型。有关其他限制,请参见上文。
      返回:
      表示循环的方法句柄。
      抛出:
      NullPointerException - 如果 startendbody 句柄中的任何一个是 null
      IllegalArgumentException - 如果任何参数违反了上面制定的规则。
      自从:
      9
      参见:
    • iteratedLoop

      public static MethodHandle  iteratedLoop(MethodHandle  iterator, MethodHandle  init, MethodHandle  body)
      构造一个循环,其范围超过 Iterator<T> 产生的值。这是 通用循环组合器 的便利包装器。

      迭代器本身将由 iterator 句柄的评估来确定。它产生的每个值都将存储在类型为 T 的循环迭代变量中。

      如果 body 句柄返回非 void 类型 V ,则还存在该类型的前导循环迭代变量。此变量使用可选的 init 句柄初始化,或者如果句柄为 null 则初始化为 V 类型的 默认值

      在每次迭代中,迭代变量都传递给 body 句柄的调用。从正文(类型为 V )返回的非 void 值更新前导迭代变量。循环句柄执行的结果将是该变量的最终 V 值(如果没有 V 变量,则为 void )。

      以下规则适用于参数句柄:

      • body 句柄不能是 null ;它的类型必须是 (V T A...)V 形式,其中 V 是非 void ,否则为 (T A...)void 。 (在 void 的情况下,我们将类型 void 分配给名称 V ,我们将编写 (V T A...)V 并理解 void 类型 V 从参数列表中悄悄删除,留下 (T A...)V 。)
      • 主体的参数列表 (V T A...) 有助于称为 internal parameter list 的类型列表。它将约束其他循环部分的参数列表。
      • 作为一种特殊情况,如果主体仅提供VT 类型,没有额外的A 类型,则内部参数列表由iterator 句柄的参数类型A... 扩展;如果它是 null,则添加单一类型 Iterable 并构成 A... 列表。
      • 如果从内部参数列表中删除迭代变量类型 (V T),则生成的较短列表 (A...) 称为 external parameter list
      • 主体返回类型 V ,如果非 void ,则确定循环的附加状态变量的类型。主体必须既接受前导参数又返回此类型的值 V
      • 如果 init 是非 null ,它必须有返回类型 V 。它的参数列表(一些 form (A*) )必须是 有效相同 到外部参数列表 (A...)
      • 如果 initnull ,循环变量将被初始化为其 默认值
      • 如果 iterator 句柄是非 null ,则它必须具有返回类型 java.util.Iterator 或其子类型。它在执行循环时产生的迭代器将假定产生可以转换为类型 T 的值。
      • null(某种形式(A*))的iterator的参数列表必须与外部参数列表(A...)有效相同。
      • 如果 iteratornull 它默认为一个行为类似于 Iterable.iterator() 的方法句柄。在那种情况下,内部参数列表 (V T A...) 必须至少有一个 A 类型,并且默认迭代器句柄参数被调整为接受领先的 A 类型,就像通过 asType 转换方法一样。领先的 A 类型必须是 Iterable 或其子类型。此转换步骤在循环构建时完成,不得抛出 WrongMethodTypeException

      T 类型可以是原语或引用。由于类型 Iterator<T> 在方法句柄表示中被擦除为原始类型 Iterator ,因此 iteratedLoop 组合器将 body 的前导参数类型调整为 Object ,就像通过 asType 转换方法一样。因此,如果在执行循环时出现错误类型的迭代器,则可能会由于 MethodHandle.asType(MethodType) 执行的动态转换而出现运行时异常。

      生成的循环句柄的结果类型和参数签名确定如下:

      • 循环句柄的结果类型是主体的结果类型V
      • 循环句柄的参数类型是外部参数列表中的 (A...) 类型。

      这是生成的循环句柄的伪代码。代码中,V /v代表循环变量的类型/值以及循环的结果类型; T /t 表示循环迭代的结构元素,A... /a... 表示传递给循环的参数。

      Iterator<T> iterator(A...); // defaults to Iterable::iterator
      V 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 注意:
      示例:
      // get an iterator from a list
      static 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 methods
      MethodHandle loop = MethodHandles.iteratedLoop(null, MH_newArrayList, MH_reverseStep);
      List<String> list = Arrays.asList("a", "b", "c", "d", "e");
      List<String> reversedList = Arrays.asList("e", "d", "c", "b", "a");
      assertEquals(reversedList, (List<String>) loop.invoke(list));
       
      ,该方法的实现可以大致表示如下:
      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);
      }
       
      参数:
      iterator - 返回迭代器以启动循环的可选句柄。如果非 null ,句柄必须返回 Iterator 或子类型。有关其他限制,请参见上文。
      init - 可选的初始化器,提供循环变量的初始值。可能是 null ,表示默认初始值。有关其他限制,请参见上文。
      body - 循环体,可能不是 null 。它控制标准情况下的循环参数和结果类型(详见上文)。它必须接受自己的返回类型(如果非空)加上一个 T 参数(用于迭代值),并且可以接受任意数量的附加类型。有关其他限制,请参见上文。
      返回:
      体现迭代循环功能的方法句柄。
      抛出:
      NullPointerException - 如果 body 句柄是 null
      IllegalArgumentException - 如果任何参数违反上述要求。
      自从:
      9
    • tryFinally

      public static MethodHandle  tryFinally(MethodHandle  target, MethodHandle  cleanup)
      通过将 target 方法句柄包装在 try-finally 块中来创建一个方法句柄。另一个方法句柄 cleanup 表示 finally 块的功能。 target 句柄执行期间抛出的任何异常都将传递给 cleanup 句柄。异常将被重新抛出,除非 cleanup handle 先抛出异常。 cleanup 句柄的执行返回的值将是 try-finally 句柄的执行结果。

      cleanup 句柄将传递一个或两个额外的前导参数。第一个是target句柄执行期间抛出的异常,如果没有抛出异常则为null。第二个是 target 句柄的执行结果,或者,如果它抛出异常,则提供所需类型的 null、零或 false 值作为占位符。如果 target 句柄具有 void 返回类型,则第二个参数不存在。 (请注意,除了参数类型转换之外,组合器通过省略相应的矛盾参数而不是通过插入 null 或零值来表示参数列表中的 void 值。)

      targetcleanup 句柄必须具有相同的对应参数和返回类型,但 cleanup 句柄可以省略尾随参数。此外,cleanup 句柄必须有一个或两个额外的前导参数:

      • 一个 Throwable ,它将携带 target 句柄抛出的异常(如果有);和
      • targetcleanup 的返回类型相同类型的参数,它将携带执行 target 句柄的结果。如果 target 返回 void,则此参数不存在。

      生成的适配器的伪代码如下所示。在代码中,V代表了try/finally构造的结果类型; A /a ,清理所消耗的结果句柄的参数类型和值;和 B /b ,那些被清理丢弃的结果句柄的参数。

      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;
      }
       

      请注意,保存的参数(伪代码中的a...)无法通过目标的执行进行修改,因此如果调用它,则将原样从调用者传递到清理。

      目标和清理必须返回相同的类型,即使清理总是抛出。要创建这样的抛出清理,请使用 throwException 组合清理逻辑,以便创建正确返回类型的方法句柄。

      请注意,tryFinally 永远不会将异常转换为正常返回。在必须以这种方式转换异常的极少数情况下,首先用 catchException(MethodHandle, Class, MethodHandle) 包装目标以捕获传出异常,然后用 tryFinally 包装。

      建议将 cleanup 的第一个参数类型声明为 Throwable 而不是更窄的子类型。这确保 cleanup 将始终被调用,无论 target 抛出什么异常。如果 target 抛出的异常类型不可分配给 cleanup 的第一个参数类型,则声明较窄的类型可能会导致 try-finally 句柄抛出 ClassCastException。请注意,原则上几乎任何类型的 Java 代码都可以抛出 VirtualMachineErrorLinkageErrorRuntimeException 的各种异常类型,并且仅捕获(比方说)IOException 的 finally 子句将掩盖 ClassCastException 后面的任何其他异常类型。

      参数:
      target - 其执行将被包装在 try 块中的句柄。
      cleanup - 在 finally 块中调用的句柄。
      返回:
      包含由两个参数组成的 try-finally 块的方法句柄。
      抛出:
      NullPointerException - 如果任何参数为空
      IllegalArgumentException - 如果 cleanup 不接受所需的前导参数,或者方法句柄类型在它们的返回类型和相应的尾随参数中不匹配
      自从:
      9
      参见:
    • tableSwitch

      public static MethodHandle  tableSwitch(MethodHandle  fallback, MethodHandle ... targets)
      创建一个表切换方法句柄,可用于根据给定的目标索引(称为选择器)切换一组目标方法句柄。

      对于 n 的选择器值,其中 n 落在 [0, N) 范围内,其中 N 是目标方法句柄的数量,表切换方法句柄将调用目标方法句柄列表中的第 n 个目标方法句柄。

      对于不在 [0, N) 范围内的选择器值,表切换方法句柄将调用给定的回退方法句柄。

      传递给此方法的所有方法句柄必须具有相同的类型,附加要求是前导参数的类型为 int 。前导参数表示选择器。

      类型中存在的任何尾随参数也将出现在返回的表切换方法句柄上。调用它时,分配给这些参数的任何参数将与选择器值一起转发到选定的方法句柄。

      API 注意:
      示例:每个案例都会删除给定的 selector 值,并采用额外的 String 参数,该参数连接(使用 String.concat(String) )到每个案例的特定常量标签字符串:
      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"));
       
      参数:
      fallback - 当选择器不在 [0, N) 范围内时调用的回退方法句柄。
      targets - 目标方法句柄数组。
      返回:
      表切换方法句柄。
      抛出:
      NullPointerException - 如果 fallbacktargets 数组或 targets 数组的任何元素是 null
      IllegalArgumentException - 如果 targets 数组为空,如果回退句柄或任何目标句柄的前导参数不是 int ,或者如果回退句柄和所有目标句柄的类型不同。
    • memorySegmentViewVarHandle

      public static VarHandle  memorySegmentViewVarHandle(ValueLayout PREVIEW  layout)
      memorySegmentViewVarHandle 是 Java 平台的预览 API。
      程序只能在启用预览功能时使用 memorySegmentViewVarHandle
      预览功能可能会在未来的版本中删除,或升级为 Java 平台的永久功能。
      创建一个 var 句柄对象,可用于取消引用 内存段PREVIEW 通过将其内容视为提供的值布局的序列。

      提供的布局指定载体类型PREVIEW , 字节大小PREVIEW , 字节对齐PREVIEW 字节顺序PREVIEW 与返回的 var 句柄关联。

      返回的 var 句柄的类型是 carrier,坐标类型列表是 (MemorySegment, long),其中 long 坐标类型对应于给定内存段中的字节偏移量。返回的 var 句柄访问给定内存段中偏移量处的字节,根据给定的字节顺序将字节组合到或从类型为 carrier 的值;生成的 var 句柄的对齐约束(以字节为单位)由 alignmentBytes 给出。

      例如,考虑由 GroupLayout 表示的内存布局PREVIEW 实例构造如下:

        GroupLayout seq = java.lang.foreign.MemoryLayout.structLayout(
            MemoryLayout.paddingLayout(32),
            ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value")
        );
       
      要访问名为 value 的成员布局,我们可以构造一个内存段视图变量句柄,如下所示:
        VarHandle handle = MethodHandles.memorySegmentViewVarHandle(ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN)); //(MemorySegment, long) -> int
        handle = MethodHandles.insertCoordinates(handle, 1, 4); //(MemorySegment) -> int
       
      API 注意:
      生成的 var 句柄具有某些特征访问模式限制,这是所有内存段视图 var 句柄所共有的。内存段视图 var 句柄与访问大小 S 和对齐约束 B 相关联(均以字节表示)。如果内存访问操作发生在与对齐约束 SB 兼容的内存地址 A 处,我们称该内存访问操作为 fully aligned。如果访问完全对齐,则支持以下访问模式并保证支持原子访问:
      • 所有T的读写访问模式,32位平台上longdouble的访问模式getset除外。
      • intlongfloatdoubleMemorySegment 的原子更新访问模式PREVIEW (JDK 的未来主要平台版本可能支持某些当前不支持的访问模式的其他类型。)
      • intlongMemorySegment 的数字原子更新访问模式PREVIEW (JDK 的未来主要平台版本可能支持某些当前不支持的访问模式的其他数字类型。)
      • intlongMemorySegment 的按位原子更新访问模式PREVIEW (JDK 的未来主要平台版本可能支持某些当前不支持的访问模式的其他数字类型。)
      如果 TfloatdoubleMemorySegment PREVIEW 然后原子更新访问模式使用它们的按位表示比较值(参见 Float.floatToRawIntBits(float) Double.doubleToRawLongBits(double) MemorySegment.address() PREVIEW , 分别)。

      或者,内存访问操作是 partially aligned 如果它发生在内存地址 A 仅与对齐约束 B 兼容;在这种情况下,访问 getset 访问模式以外的任何内容都将导致 IllegalStateException 。如果访问是部分对齐的,则原子访问只保证关于 AS 的 GCD 的最大幂。

      在所有其他情况下,我们称内存访问操作为 misaligned ;在这种情况下,无论使用何种访问模式,都会抛出 IllegalStateException

      最后,如果 TMemorySegment 所有写访问模式都会抛出 IllegalArgumentException 除非要写入的值是 本国的PREVIEW 内存段。

      参数:
      layout - 要为其获取内存访问句柄的值布局。
      返回:
      新的内存段视图 var 句柄。
      抛出:
      IllegalArgumentException - 如果使用了非法载体类型,或者如果 alignmentBytes 不是 2 的幂。
      NullPointerException - 如果 layoutnull
      自从:
      19
      参见:
    • filterValue

      public static VarHandle  filterValue(VarHandle  target, MethodHandle  filterToTarget, MethodHandle  filterFromTarget)
      filterValue 是 Java 平台的预览 API。
      程序只能在启用预览功能时使用 filterValue
      预览功能可能会在未来的版本中删除,或升级为 Java 平台的永久功能。
      过滤器函数预处理传入和传出值来调整目标 var 句柄。

      当在生成的 var 句柄上调用 eg VarHandle.set(Object...) 时,传入值(类型为 T ,其中 T 是第一个过滤器函数的 last 参数类型)使用第一个过滤器进行处理,然后传递给目标 var 句柄。相反,当在生成的 var 句柄上调用 eg VarHandle.get(Object...) 时,从目标 var 句柄(类型 T ,其中 T 是第二个过滤器函数的 last 参数类型)获得的返回值使用第二个过滤器处理并返回给调用者.更高级的访问模式类型,例如 VarHandle.AccessMode.COMPARE_AND_EXCHANGE 可能会同时应用这两个过滤器。

      为了使装箱和拆箱过滤器格式正确,它们的类型必须分别为 (A... , S) -> T(A... , T) -> S 形式,其中 T 是目标变量句柄的类型。如果是这种情况,生成的 var 句柄将具有类型 S 并将具有附加坐标 A...(将附加到目标 var 句柄的坐标)。

      如果装箱和拆箱过滤器在调用时抛出任何已检查的异常,则生成的 var 句柄将抛出 IllegalStateException

      生成的 var 句柄将具有与目标 var 句柄相同的访问模式(请参阅 VarHandle.AccessMode )和原子访问保证。

      参数:
      target - 目标变量句柄
      filterToTarget - 将某些类型 S 转换为 target 类型的过滤器
      filterFromTarget - 将 target 类型转换为某种类型 S 的过滤器
      返回:
      接受新类型的适配器变量句柄,执行提供的装箱/拆箱转换。
      抛出:
      IllegalArgumentException - 如果 filterFromTargetfilterToTarget 格式不正确,也就是说,它们分别具有 (A... , S) -> T(A... , T) -> S 以外的类型,其中 T 是目标 var 句柄的类型,或者如果确定 filterFromTargetfilterToTarget 抛出任何已检查的异常.
      NullPointerException - 如果任何参数是 null
      自从:
      19
    • filterCoordinates

      public static VarHandle  filterCoordinates(VarHandle  target, int pos, MethodHandle ... filters)
      filterCoordinates 是 Java 平台的预览 API。
      程序只能在启用预览功能时使用 filterCoordinates
      预览功能可能会在未来的版本中删除,或升级为 Java 平台的永久功能。
      通过使用一元过滤函数预处理传入的坐标值来调整目标变量句柄。

      当在生成的 var 句柄上调用 eg VarHandle.get(Object...) 时,从位置 pos 开始的传入坐标值(类型 C1, C2 ... Cn ,其中 C1, C2 ... Cn 是一元过滤函数的返回类型)被转换为新值(类型 S1, S2 ... Sn ,其中 S1, S2 ... Sn 是参数一元过滤器函数的类型),然后传递(连同适配未更改的任何坐标)到目标 var 句柄。

      对于格式正确的坐标过滤器,它们的类型必须是 S1 -> T1, S2 -> T1 ... Sn -> Tn 形式,其中 T1, T2 ... Tn 是从目标变量句柄的位置 pos 开始的坐标类型。

      如果任何过滤器在调用时抛出检查异常,则生成的 var 句柄将抛出 IllegalStateException

      生成的 var 句柄将具有与目标 var 句柄相同的访问模式(请参阅 VarHandle.AccessMode )和原子访问保证。

      参数:
      target - 目标变量句柄
      pos - 要变换的第一个坐标的位置
      filters - 用于转换从位置 pos 开始的坐标的一元函数
      返回:
      接受新坐标类型的适配器变量句柄,将提供的转换应用于新坐标值。
      抛出:
      IllegalArgumentException - 如果 filters 中的句柄格式不正确,即它们具有 S1 -> T1, S2 -> T2, ... Sn -> Tn 以外的类型,其中 T1, T2 ... Tn 是从目标变量句柄的位置 pos 开始的坐标类型,如果 pos 不在 0 和目标变量句柄坐标之间arity,inclusive,或者如果提供的过滤器比从 pos 开始的可用坐标类型的实际数量更多,或者如果确定任何过滤器抛出任何已检查的异常。
      NullPointerException - 如果任何参数是 nullfilters 包含 null
      自从:
      19
    • insertCoordinates

      public static VarHandle  insertCoordinates(VarHandle  target, int pos, Object ... values)
      insertCoordinates 是 Java 平台的预览 API。
      程序只能在启用预览功能时使用 insertCoordinates
      预览功能可能会在未来的版本中删除,或升级为 Java 平台的永久功能。
      在调用 var 句柄之前,为目标 var 句柄提供一个或多个 bound coordinates。因此,生成的 var 句柄将具有比目标 var 句柄更少的坐标类型。

      当在生成的 var 句柄上调用 eg VarHandle.get(Object...) 时,传入的坐标值与绑定坐标值连接,然后传递给目标 var 句柄。

      为了使绑定坐标格式正确,它们的类型必须是 T1, T2 ... Tn ,其中 T1, T2 ... Tn 是从目标 var 句柄的位置 pos 开始的坐标类型。

      生成的 var 句柄将具有与目标 var 句柄相同的访问模式(请参阅 VarHandle.AccessMode )和原子访问保证。

      参数:
      target - 插入绑定坐标后要调用的 var 句柄
      pos - 要插入的第一个坐标的位置
      values - 要插入的一系列绑定坐标
      返回:
      在调用目标变量句柄之前插入附加坐标的适配器变量句柄
      抛出:
      IllegalArgumentException - 如果 pos 不在 0 和目标 var 句柄坐标 arity 之间,包括在内,或者如果提供的值多于从 pos 开始的可用坐标类型的实际数量。
      ClassCastException - 如果 values 中的绑定坐标格式不正确,即它们的类型不是 T1, T2 ... Tn ,其中 T1, T2 ... Tn 是从目标变量句柄的位置 pos 开始的坐标类型。
      NullPointerException - 如果任何参数是 nullvalues 包含 null
      自从:
      19
    • permuteCoordinates

      public static VarHandle  permuteCoordinates(VarHandle  target, List <Class <?>> newCoordinates, int... reorder)
      permuteCoordinates 是 Java 平台的预览 API。
      程序只能在启用预览功能时使用 permuteCoordinates
      预览功能可能会在未来的版本中删除,或升级为 Java 平台的永久功能。
      提供一个 var 句柄,它通过重新排列目标 var 句柄的坐标值来调整它们,以便新坐标与提供的坐标相匹配。

      给定的数组控制重新排序。调用 #I 传入坐标数(值 newCoordinates.size() ),并调用 #O 传出坐标数(与目标 var 句柄关联的坐标数)。那么重新排序数组的长度必须是 #O ,并且每个元素必须是小于 #I 的非负数。对于每一个小于 #ON,第 N 个输出坐标将从第 I 个输入坐标中获取,其中 Ireorder[N]

      不应用坐标值转换。 newCoordinates 确定的每个传入坐标的类型必须与目标 var 句柄中相应传出坐标的类型相同。

      重新排序的数组不需要指定实际的排列。如果传入坐标的索引在数组中出现多次,则传入坐标将被复制;如果传入坐标的索引未出现在数组中,则传入坐标将被丢弃。

      生成的 var 句柄将具有与目标 var 句柄相同的访问模式(请参阅 VarHandle.AccessMode )和原子访问保证。

      参数:
      target - 坐标重新排序后要调用的 var 句柄
      newCoordinates - 新坐标类型
      reorder - 控制重新排序的索引数组
      返回:
      在调用目标变量句柄之前重新排列传入坐标值的适配器变量句柄
      抛出:
      IllegalArgumentException - 如果索引数组长度不等于目标 var 句柄的坐标数,或者如果任何索引数组元素不是 newCoordinates 坐标的有效索引,或者如果目标 var 句柄中的两个对应坐标类型和在 newCoordinates 中不相同。
      NullPointerException - 如果任何参数是 nullnewCoordinates 包含 null
      自从:
      19
    • collectCoordinates

      public static VarHandle  collectCoordinates(VarHandle  target, int pos, MethodHandle  filter)
      collectCoordinates 是 Java 平台的预览 API。
      程序只能在启用预览功能时使用 collectCoordinates
      预览功能可能会在未来的版本中删除,或升级为 Java 平台的永久功能。
      通过使用过滤器(方法句柄)预处理其坐标值的子序列来调整目标变量句柄。预处理的坐标被过滤函数的结果(如果有的话)替换,然后在修改后的(通常是缩短的)坐标列表上调用目标变量句柄。

      如果 R 是过滤器的返回类型(不能为空),则目标 var 句柄必须接受类型为 R 的值作为其在位置 pos 的坐标,之前和/或之后是任何未传递给过滤器的坐标。没有坐标被重新排序,并且从过滤器返回的结果替换(按顺序)最初传递给适配器的整个坐标子序列。

      过滤器的参数类型(如果有的话)在生成的适配变量句柄中替换位置 pos 处的目标变量句柄的零个或一个坐标类型。过滤器的返回类型必须与位置 pos 处的目标变量句柄的坐标类型相同,并且该目标变量句柄坐标由过滤器的返回值提供。

      如果任何过滤器在调用时抛出检查异常,则生成的 var 句柄将抛出 IllegalStateException

      生成的 var 句柄将具有与目标 var 句柄相同的访问模式(请参阅 VarHandle.AccessMode )和原子访问保证。

      参数:
      target - 过滤坐标后要调用的 var 句柄
      pos - 待过滤坐标的位置
      filter - 过滤器方法句柄
      返回:
      在调用目标变量句柄之前过滤传入坐标值的适配器变量句柄
      抛出:
      IllegalArgumentException - 如果 filter 的返回类型为 void,或者它与目标 var 句柄的 pos 坐标不同,如果 pos 不在 0 和目标 var 句柄坐标之间,包括在内,如果生成的 var 句柄的类型将有 坐标太多 ,或者如果确定 filter 抛出任何已检查的异常。
      NullPointerException - 如果任何参数是 null
      自从:
      19
    • dropCoordinates

      public static VarHandle  dropCoordinates(VarHandle  target, int pos, Class <?>... valueTypes)
      dropCoordinates 是 Java 平台的预览 API。
      程序只能在启用预览功能时使用 dropCoordinates
      预览功能可能会在未来的版本中删除,或升级为 Java 平台的永久功能。
      返回一个 var 句柄,它将在委托给目标 var 句柄之前丢弃一些虚拟坐标。因此,生成的 var 句柄将具有比目标 var 句柄更多的坐标类型。

      pos 参数的范围可能介于零和N, 在哪里N是目标变量句柄坐标类型的元数。如果 pos 为零,虚拟坐标将在目标的实际参数之前;如果posN他们会来的。

      生成的 var 句柄将具有与目标 var 句柄相同的访问模式(请参阅 VarHandle.AccessMode )和原子访问保证。

      参数:
      target - 删除虚拟坐标后要调用的 var 句柄
      pos - 要放置的第一个坐标的位置(最左边为零)
      valueTypes - 要放置的坐标类型
      返回:
      一个适配器变量句柄,它在调用目标变量句柄之前删除一些虚拟坐标
      抛出:
      IllegalArgumentException - 如果 pos 不在 0 和目标 var 句柄坐标 arity 之间,包括在内。
      NullPointerException - 如果任何参数是 nullvalueTypes 包含 null
      自从:
      19