モジュール java.base
パッケージ java.lang.invoke

クラスMethodHandles


  • public class MethodHandles
    extends Object
    このクラスは、メソッド・ハンドルに対する処理を行うかメソッド・ハンドルを返すstaticメソッドだけで構成されます。 それらはいくつかのカテゴリに分類されます。
    • メソッドやフィールドのメソッド・ハンドルの作成に役立つルックアップ・メソッド。
    • 既存のメソッド・ハンドルを組み合わせたり変換したりして新しいハンドルを作成するコンビネータ・メソッド。
    • その他の一般的なJVM操作や制御フロー・パターンをエミュレートするメソッド・ハンドルを作成する、その他のファクトリ・メソッド。
    導入されたバージョン:
    1.7
    • ネストされたクラスのサマリー

      ネストされたクラス 
      修飾子と型 クラス 説明
      static class  MethodHandles.Lookup
      ルックアップ・オブジェクトは、メソッド・ハンドルの作成にアクセス・チェックが必要な場合のメソッド・ハンドル作成用ファクトリです。
    • メソッドの詳細

      • lookup

        public static MethodHandles.Lookup lookup()
        呼出し元のすべてのサポートされるバイトコード動作をエミュレートするためのフル機能を持つルックアップ・オブジェクトを返します。 これらの機能には呼出し元へのprivateアクセスが含まれます。 ルックアップ・オブジェクトのファクトリ・メソッドは、呼出し元がバイトコードを介してアクセスするメンバー(protectedおよびprivateのフィールドおよびメソッドを含む)の直接メソッド・ハンドルを作成できます。 このルックアップ・オブジェクトは、信頼できるエージェントに委譲可能な1つの機能です。 信頼できないコードからアクセス可能な場所に格納しないでください。

        このメソッドは呼出し元依存です。つまり、呼出し元ごとに異なる値を返す可能性があります。

        戻り値:
        このメソッドの呼出し元用のルックアップ・オブジェクト、privateアクセス
      • publicLookup

        public static MethodHandles.Lookup publicLookup()
        最小の信頼レベルを持つルックアップ・オブジェクトを返します。 ルックアップには、PUBLICモードとUNCONDITIONALモードがあります。 無条件にエクスポートされるパッケージ内のpublicクラスのpublicメンバーに対するメソッド・ハンドルを作成するためにのみ使用できます。

        単に慣例により、このルックアップ・オブジェクトのルックアップ・クラスは、Objectになります。

        APIのノート:
        Objectの使用は従来型であり、参照モードが制限されているため、Objectの内部、そのパッケージまたはそのモジュールへの特別なアクセスは提供されません。 したがって、このルックアップ・オブジェクトのルックアップ・コンテキストはブートストラップ・クラス・ローダーになります。つまり、ユーザー・クラスを見つけることができません。

        ディスカッション:参照クラスは、publicLookup().in(C.class)形式の式を使用して他のクラスCに変更できますが、クラス・ローダーを変更することで参照コンテキストを変更できます。 publicルックアップ・オブジェクトは常にセキュリティ・マネージャ・チェックが適用されます。 また、呼出し元依存メソッドにアクセスすることもできません。

        戻り値:
        最小限の信頼されるルックアップ・オブジェクト
      • privateLookupIn

        public static MethodHandles.Lookup privateLookupIn​(Class<?> targetClass,
                                                           MethodHandles.Lookup lookup)
                                                    throws IllegalAccessException
        ターゲット・クラスで、サポートされているすべてのバイトコード動作(プライベート・アクセスを含む)をエミュレートする完全な機能を備えたlookup objectを返します。 このメソッドは、Lookupオブジェクトとして指定されたコール元が、ターゲット・クラスに対してディープ・リフレクションを実行できるかどうかをチェックします。 m1lookup classを含むモジュールで、m2がターゲット・クラスを含むモジュールである場合、このチェックによって次のことが確認されます。
        • m1 reads m2.
        • ターゲット・クラスを含むパッケージをm1以上にopensします。
        • このルックアップには、MODULEルックアップ・モードがあります。

        セキュリティ・マネージャが存在する場合は、そのcheckPermissionメソッドがコールされ、ReflectPermission("suppressAccessChecks")がチェックされます。

        APIのノート:
        MODULE参照モードは、参照オブジェクトがコール元モジュールのコードによって作成された(またはコール元によって最初に作成された参照オブジェクトから導出された)ことを認証します。 MODULE参照モードのルックアップ・オブジェクトは、コール元へのPRIVATEおよびPACKAGEアクセス権を付与せずに、信頼できるパーティと共有できます。
        パラメータ:
        targetClass - ターゲット・クラス
        lookup - 呼出し側参照オブジェクト
        戻り値:
        プライベート・アクセスを持つターゲット・クラスの参照オブジェクト
        例外:
        IllegalArgumentException - targetClassがプリミティブ型または配列クラスである場合
        NullPointerException - targetClassまたはcallernullの場合
        IllegalAccessException - 前述のアクセス・チェックが失敗した場合
        SecurityException - セキュリティ・マネージャによって拒否された場合
        導入されたバージョン:
        9
        関連項目:
        MethodHandles.Lookup.dropLookupMode(int)
      • reflectAs

        public static <T extends Member> T reflectAs​(Class<T> expected,
                                                     MethodHandle target)
        直接メソッド・ハンドルの未チェックの解読を実行します。 結果は、ユーザーがターゲット・メソッド・ハンドルを解決するのに十分な機能を持つルックアップ・オブジェクトを取得し、ターゲットでLookup.revealDirectを呼び出してシンボリック参照を取得し、MethodHandleInfo.reflectAsを呼び出してシンボリック参照をメンバーに解決したかのようになります。

        セキュリティ・マネージャが存在する場合は、そのcheckPermissionメソッドがReflectPermission("suppressAccessChecks")アクセス権で呼び出されます。

        型パラメータ:
        T - 結果に期待する型(Memberまたはサブタイプ)
        パラメータ:
        target - シンボリック参照コンポーネントに解決する直接メソッド・ハンドル
        expected - 期待する結果型Tを表すクラス・オブジェクト
        戻り値:
        メソッド、コンストラクタまたはフィールド・オブジクトへの参照
        例外:
        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が配列型でない場合
        導入されたバージョン:
        9
        関連項目:
        Array.newInstance(Class, int)
        The Java™Virtual Machine Specificationを参照してください。
        6.5 anewarray命令
      • arrayLength

        public static MethodHandle arrayLength​(Class<?> arrayClass)
                                        throws IllegalArgumentException
        配列の長さを戻すメソッド・ハンドルを、arraylengthバイトコードのように生成します。 メソッド・ハンドルの型は戻り型としてintを持ち、その唯一の引数は配列型になります。

        戻されたメソッド・ハンドルがnull配列参照で呼び出されると、NullPointerExceptionがスローされます。

        パラメータ:
        arrayClass - 配列の型
        戻り値:
        指定された配列型の配列の長さを取得できるメソッド・ハンドル
        例外:
        NullPointerException - 引数がnullの場合
        IllegalArgumentException - arrayClassが配列型でない場合
        導入されたバージョン:
        9
        The Java™Virtual Machine Specificationを参照してください。
        6.5 arraylength命令
      • arrayElementGetter

        public static MethodHandle arrayElementGetter​(Class<?> arrayClass)
                                               throws IllegalArgumentException
        aaloadバイトコードのように、配列の要素への読取りアクセス権を付与するメソッド・ハンドルを生成します。 メソッド・ハンドルの型に含まれる戻り値の型は、配列の要素の型になります。 その最初の引数は配列の型、2番目の引数はintになります。

        戻されたメソッド・ハンドルが呼び出されると、配列参照および配列索引がチェックされます。 NullPointerExceptionは、配列参照がnullの場合にスローされ、索引が負の場合、または索引が配列の長さ以上である場合はArrayIndexOutOfBoundsExceptionがスローされます。

        パラメータ:
        arrayClass - 配列の型
        戻り値:
        指定された配列型から値をロードできるメソッド・ハンドル
        例外:
        NullPointerException - 引数がnullの場合
        IllegalArgumentException - arrayClassが配列型でない場合
        The Java™Virtual Machine Specificationを参照してください。
        6.5 aaload命令
      • arrayElementSetter

        public static MethodHandle arrayElementSetter​(Class<?> arrayClass)
                                               throws IllegalArgumentException
        配列の要素への書込みアクセス権を付与するメソッド・ハンドルを、astoreバイトコードのように生成します。 このメソッド・ハンドルの型に含まれる戻り値の型は、voidになります。 その最後の引数は、配列の要素の型になります。 最初と2番目の引数は、配列の型とintになります。

        戻されたメソッド・ハンドルが呼び出されると、配列参照および配列索引がチェックされます。 NullPointerExceptionは、配列参照がnullの場合にスローされ、索引が負の場合、または索引が配列の長さ以上である場合はArrayIndexOutOfBoundsExceptionがスローされます。

        パラメータ:
        arrayClass - 配列のクラス
        戻り値:
        配列型に値を格納できるメソッド・ハンドル
        例外:
        NullPointerException - 引数がnullの場合
        IllegalArgumentException - arrayClassが配列型でない場合
        The Java™Virtual Machine Specificationを参照してください。
        6.5 aastore命令
      • arrayElementVarHandle

        public static VarHandle arrayElementVarHandle​(Class<?> arrayClass)
                                               throws IllegalArgumentException
        arrayClass型の配列の要素へのアクセス権を付与するVarHandleを生成します。 VarHandleの変数型はarrayClassのコンポーネント型で、座標型のリストは(arrayClass, int)です。int座標型は、配列への索引である引数に対応します。

        返されるVarHandleの特定のアクセス・モードは、次の条件下ではサポートされません。

        • コンポーネント・タイプがbyteshortcharintlongfloatまたはdouble以外の場合、数値アトミック更新アクセス・モードはサポートされません。
        • フィールド・タイプがbooleanbyteshortcharintまたはlong以外の場合、ビット単位のアトミック更新アクセス・モードはサポートされていません。

        コンポーネント・タイプがfloatまたはdoubleの場合、数値およびアトミック更新アクセス・モードは、ビット単位の表現を使用して値を比較します(それぞれFloat.floatToRawIntBits(float)およびDouble.doubleToRawLongBits(double)を参照)。

        戻されたVarHandleが呼び出されると、配列参照および配列索引がチェックされます。 NullPointerExceptionは、配列参照がnullの場合にスローされ、索引が負の場合、または索引が配列の長さ以上である場合はArrayIndexOutOfBoundsExceptionがスローされます。

        APIのノート:
        数値およびアトミック更新アクセス・モードで実行されるfloat値またはdouble値のビット単位比較は、プリミティブの==演算子およびFloat.equals(java.lang.Object)およびDouble.equals(java.lang.Object)メソッド(特にNaN値の比較または-0.0+0.0の比較)とは異なります。 比較、設定、またはそのような値との比較および交換操作を実行する場合は、操作が予期せず失敗する可能性があるため、注意が必要です。 JavaではNaNとみなされる可能性のある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がnullの場合
        IllegalArgumentException - arrayClassが配列型でない場合
        導入されたバージョン:
        9
      • byteArrayViewVarHandle

        public static VarHandle byteArrayViewVarHandle​(Class<?> viewArrayClass,
                                                       ByteOrder byteOrder)
                                                throws IllegalArgumentException
        int[]long[]など、別のプリミティブ配列型であるかのように表示されるbyte[]配列の要素へのアクセス権を付与するVarHandleを生成します。 VarHandleの変数型はviewArrayClassのコンポーネント型で、座標型のリストは(byte[], int)です。int座標型は、byte[]配列への索引である引数に対応します。 戻されたVarHandleは、byte[]配列内の索引のバイトにアクセスし、指定されたエンディアンに従って、viewArrayClassのコンポーネント・タイプの値との間でバイトを構成します。

        サポートされているコンポーネント・タイプ(変数タイプ)は、shortcharintlongfloatおよびdoubleです。

        索引が0より小さいか、byte[]配列の長さからTのサイズ(バイト)を引いた値より大きい場合、特定の索引でバイトにアクセスすると、IndexOutOfBoundsExceptionが発生します。

        索引のバイト・アクセスは、配列および索引に関連付けられた基礎となるメモリー・アドレス(Aなど)に関して、Tに対して位置合せまたは位置合せが誤っている場合があります。 アクセスの境界が誤っている場合、getおよびsetアクセス・モード以外のアクセスはIllegalStateExceptionになります。 このような場合、アトミック・アクセスは、AのGCDとTのサイズ(バイト)を割った2つの最大電力に対してのみ保証されます。 アクセスが整列されている場合は、次のアクセスモードがサポートされ、アトミックアクセスが保証されます。

        • すべてのTの読取り/書込みアクセス・モード。ただし、アクセス・モードはlongの場合はget、32ビット・プラットフォームの場合はdoubleです。
        • intlongfloatまたはdoubleのアトミック更新アクセス・モード。 (JDKの将来のメジャー・プラットフォーム・リリースでは、現在サポートされていない特定のアクセス・モードの追加タイプがサポートされる場合があります。)
        • intおよびlongの数値アトミック更新アクセス・モード。 (JDKの将来のメジャー・プラットフォーム・リリースでは、現在サポートされていない特定のアクセス・モードの追加の数値タイプがサポートされる場合があります。)
        • intおよびlongのビット単位のアトミック更新アクセス・モード。 (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;
         

        変数の型がfloatまたはdoubleの場合、アトミック更新アクセス・モードは、ビット単位表現を使用して値を比較します(それぞれFloat.floatToRawIntBits(float)およびDouble.doubleToRawLongBits(double)を参照)。

        パラメータ:
        viewArrayClass - T型のコンポーネント・タイプを持つビュー配列クラス
        byteOrder - 基礎となるbyte配列に格納されるビュー配列要素のエンディアン
        戻り値:
        ビュー配列クラスのコンポーネント・タイプに対応する要素として表示されるbyte[]配列の要素へのアクセス権を付与するVarHandle
        例外:
        NullPointerException - viewArrayClassまたはbyteOrderがnullの場合
        IllegalArgumentException - viewArrayClassが配列型でない場合
        UnsupportedOperationException - viewArrayClassのコンポーネント型が変数型としてサポートされていない場合
        導入されたバージョン:
        9
      • byteBufferViewVarHandle

        public static VarHandle byteBufferViewVarHandle​(Class<?> viewArrayClass,
                                                        ByteOrder byteOrder)
                                                 throws IllegalArgumentException
        ByteBufferの要素へのアクセス権を付与するVarHandleを生成します。これは、int[]long[]など、byteの要素とは異なるプリミティブ・コンポーネント型の要素の配列であるかのように表示されます。 VarHandleの変数型はviewArrayClassのコンポーネント型で、座標型のリストは(ByteBuffer, int)です。int座標型は、byte[]配列への索引である引数に対応します。 戻されたVarHandleは、ByteBuffer内の索引のバイトにアクセスし、指定されたエンディアンに従って、viewArrayClassのコンポーネント・タイプの値との間でバイトを構成します。

        サポートされているコンポーネント・タイプ(変数タイプ)は、shortcharintlongfloatおよびdoubleです。

        ByteBufferが読取り専用の場合、アクセスは読取りアクセス・モード以外のものに対してReadOnlyBufferExceptionになります。

        索引が0より小さいか、ByteBuffer制限からTのサイズ(バイト)を引いた値より大きい場合、特定の索引のバイト・アクセスはIndexOutOfBoundsExceptionになります。

        索引のバイト・アクセスは、ByteBufferおよび索引に関連付けられた基礎となるメモリー・アドレス(Aなど)に関して、Tに対して位置合せまたは位置合せが誤っている場合があります。 アクセスの境界が誤っている場合、getおよびsetアクセス・モード以外のアクセスはIllegalStateExceptionになります。 このような場合、アトミック・アクセスは、AのGCDとTのサイズ(バイト)を割った2つの最大電力に対してのみ保証されます。 アクセスが整列されている場合は、次のアクセスモードがサポートされ、アトミックアクセスが保証されます。

        • すべてのTの読取り/書込みアクセス・モード。ただし、アクセス・モードはlongの場合はget、32ビット・プラットフォームの場合はdoubleです。
        • intlongfloatまたはdoubleのアトミック更新アクセス・モード。 (JDKの将来のメジャー・プラットフォーム・リリースでは、現在サポートされていない特定のアクセス・モードの追加タイプがサポートされる場合があります。)
        • intおよびlongの数値アトミック更新アクセス・モード。 (JDKの将来のメジャー・プラットフォーム・リリースでは、現在サポートされていない特定のアクセス・モードの追加の数値タイプがサポートされる場合があります。)
        • intおよびlongのビット単位のアトミック更新アクセス・モード。 (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;
         

        変数の型がfloatまたはdoubleの場合、アトミック更新アクセス・モードは、ビット単位表現を使用して値を比較します(それぞれFloat.floatToRawIntBits(float)およびDouble.doubleToRawLongBits(double)を参照)。

        パラメータ:
        viewArrayClass - T型のコンポーネント・タイプを持つビュー配列クラス
        byteOrder - 基礎となるByteBufferに格納されたビュー配列要素のエンディアン(ByteBufferのエンディアンより優先されることに注意してください)
        戻り値:
        ビュー配列クラスのコンポーネント・タイプに対応する要素として表示されるByteBufferの要素へのアクセス権を付与するVarHandle
        例外:
        NullPointerException - viewArrayClassまたはbyteOrderがnullの場合
        IllegalArgumentException - viewArrayClassが配列型でない場合
        UnsupportedOperationException - viewArrayClassのコンポーネント型が変数型としてサポートされていない場合
        導入されたバージョン:
        9
      • spreadInvoker

        public static MethodHandle spreadInvoker​(MethodType type,
                                                 int leadingArgCount)
        指定されたtypeの任意のメソッド・ハンドルを呼び出すメソッド・ハンドルを生成しますが、その際、指定された数の末尾の引数が単一の末尾のObject[]配列で置き換えられます。 結果となるインボーカは、次の引数を持つメソッド・ハンドルです。
        • 単一のMethodHandleターゲット
        • 0個以上の先頭の値(個数はleadingArgCount)
        • 末尾の引数を含むObject[]配列

        インボーカがそのターゲットを呼び出す方法は、示されたtypeを使用したinvokeの呼出しに似ています。 つまりその動作は、ターゲットの型が指定された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がnullである場合
        IllegalArgumentException - leadingArgCountが0からtype.parameterCount()(含む)までの範囲でない場合、または結果のメソッド・ハンドルの型のパラメータ数が多すぎる場合
      • exactInvoker

        public static MethodHandle exactInvoker​(MethodType type)
        特殊なインボーカ・メソッド・ハンドルを生成します(これを使用すれば、指定された型の任意のメソッド・ハンドルを、invokeExactを使用する場合と同様に呼び出すことができる)。 結果となるインボーカの型は、MethodHandle型の追加の先頭の引数を1つ受け取る点を除けば、目的の型とまったく等しくなります。

        このメソッドは次のコードと同等です(ただし、効率はおそらくこのメソッドのほうが高い)。 publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)

        解説: インボーカ・メソッド・ハンドルは、未知の型のメソッド・ハンドル変数を操作する場合に役立つ可能性があります。 たとえば、メソッド・ハンドル変数MへのinvokeExact呼出しをエミュレートするには、その型Tを抽出し、T用のインボーカ・メソッドXを検索し、インボーカ・メソッドをX.invoke(T, A...)のように呼び出します。 (型Tが未知であるため、X.invokeExactの呼出しは機能しない。) 分配や収集などの引数変換が必要な場合は、それらをインボーカXに一度だけ適用しておけば、Mのさまざまなメソッド・ハンドル値(ただしXの型と互換性があるものにかぎる)で再利用できます。

        (ノート: Core Reflection API経由でインボーカ・メソッドを使用することはできません。 宣言されたinvokeExactまたはinvokeメソッドでjava.lang.reflect.Method.invokeを呼び出そうとすると、UnsupportedOperationExceptionが発行されます。)

        このメソッドでは、リフレクションやセキュリティに関する例外はスローされません。

        パラメータ:
        type - 目的となるターゲットの型
        戻り値:
        指定された型の任意のメソッド・ハンドルの呼出しに適したメソッド・ハンドル
        例外:
        IllegalArgumentException - 結果のメソッド・ハンドルの型のパラメータ数が多すぎる場合
      • invoker

        public static MethodHandle invoker​(MethodType type)
        特殊なインボーカ・メソッド・ハンドルを生成します(これを使用すれば、指定された型と互換性のある任意のメソッド・ハンドルを、invokeを使用する場合と同様に呼び出すことができる)。 結果となるインボーカの型は、MethodHandle型の追加の先頭の引数を1つ受け取る点を除けば、目的の型とまったく等しくなります。

        ターゲットが期待される型と異なっている場合、インボーカはそのターゲットを呼び出す前に、asTypeの場合と同じように、参照キャストを必要に応じて適用するほか、プリミティブ値のボクシング、アンボクシング、またはワイドニングを行います。 同様に、戻り値も必要に応じて変換されます。 ターゲットが可変引数メソッド・ハンドルの場合は、やはりasTypeの場合と同じように、必要な引数変換が行われます。

        このメソッドは次のコードと同等です(ただし、効率はおそらくこのメソッドのほうが高い)。 publicLookup().findVirtual(MethodHandle.class, "invoke", type)

        ディスカッション: 一般的なメソッド型は、Object引数および戻り値のみを言及するものです。 そのような型のインボーカは、引数の数が汎用型と同じメソッド・ハンドルであれば任意のものを呼び出すことができます。

        (ノート: Core Reflection API経由でインボーカ・メソッドを使用することはできません。 宣言されたinvokeExactまたはinvokeメソッドでjava.lang.reflect.Method.invokeを呼び出そうとすると、UnsupportedOperationExceptionが発行されます。)

        このメソッドでは、リフレクションやセキュリティに関する例外はスローされません。

        パラメータ:
        type - 目的となるターゲットの型
        戻り値:
        指定された型に変換可能な任意のメソッド・ハンドルの呼出しに適したメソッド・ハンドル
        例外:
        IllegalArgumentException - 結果のメソッド・ハンドルの型のパラメータ数が多すぎる場合
      • varHandleExactInvoker

        public static MethodHandle varHandleExactInvoker​(VarHandle.AccessMode accessMode,
                                                         MethodType type)
        関連するアクセス・モード・タイプが指定されたタイプと互換性があるVarHandleで署名多相アクセス・モード・メソッドを起動するために使用できる特別なインボーカ・メソッド・ハンドルを生成します。 結果の呼出し元には、VarHandle型の追加の先行引数を受け入れることを除き、目的の指定された型と完全に等しい型があります。
        パラメータ:
        accessMode - VarHandleアクセス・モード
        type - 目的となるターゲットの型
        戻り値:
        アクセス・モード・タイプが指定された型であるVarHandleのアクセス・モード・メソッドの起動に適したメソッド・ハンドル。
        導入されたバージョン:
        9
      • varHandleInvoker

        public static MethodHandle varHandleInvoker​(VarHandle.AccessMode accessMode,
                                                    MethodType type)
        関連するアクセス・モード・タイプが指定されたタイプと互換性がある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の場合と同じ変換が許可されるほか、それらの変換が失敗した場合には、いくつかの追加の変換も適用されます。 asTypeで行われる変換の前に、あるいはその代わりに、次のいずれかの変換が可能であれば適用されます(T0T1は型)。

        • T0T1が参照であり、T1がインタフェース型である場合は、型T0の値がキャストなしでT1として渡されます。 (インタフェースのこの扱いは、バイトコード・ベリファイアの使用法に従ったものです。)
        • T0がbooleanでT1が別のプリミティブの場合、booleanがバイト値に変換されます(trueは1、falseは0)。 (この扱いは、バイトコード・ベリファイアの使用法に従ったものです。)
        • T1がbooleanでT0が別のプリミティブの場合、Javaキャスト変換(JLS 5.5)によってT0がbyteに変換され、結果の下位ビットのテストが、(x & 1)!= 0と同様に行われます。
        • T0T1がboolean以外のプリミティブの場合、Javaキャスト変換(JLS 5.5)が適用されます。 (具体的には、ワイドニングやナローイングによってT0T1に変換される。)
        • T0が参照でT1がプリミティブの場合は、実行時にアンボクシング変換が適用されますが、そのあと、プリミティブ値に対してJavaキャスト変換(JLS 5.5)が行われる可能性があり、さらに下位ビットのテストによるbyteからbooleanへの変換が行われる可能性もあります。
        • T0が参照でT1がプリミティブの場合、実行時に参照がnullであれば、値ゼロが導入されます。

        パラメータ:
        target - 引数の型を調整したあとに呼び出すメソッド・ハンドル
        newType - 新しいメソッド・ハンドルの期待される型
        戻り値:
        必要な引数変換をすべて実行したあとでターゲットに委譲し、必要なあらゆる戻り値変換の手配も行うメソッド・ハンドル
        例外:
        NullPointerException - どちらかの引数がnullの場合
        WrongMethodTypeException - 変換できない場合
        関連項目:
        MethodHandle.asType(java.lang.invoke.MethodType)
      • permuteArguments

        public static MethodHandle permuteArguments​(MethodHandle target,
                                                    MethodType newType,
                                                    int... reorder)
        引数の順序を変更することによって、指定されたメソッド・ハンドルの呼出し順序を新しい型に適応させるメソッド・ハンドルを生成します。 結果のメソッド・ハンドルが目的の新しい型と等しい型を報告することが、保証されます。

        指定された配列によって並べ替えが制御されます。 入力パラメータの数(値newType.parameterCount())を#I、出力パラメータの数(値target.type().parameterCount())を#Oとします。 このとき、並べ替え配列の長さは#O、各要素は#Iより小さい負でない数でなければいけません。 #Oより小さいすべてのNについて、N番目の出力引数はI番目の入力引数から取られます(Ireorder[N])。

        引数や戻り値の変換は一切適用されません。 各入力引数の型(newTypeによって決定される)は、ターゲット・メソッド・ハンドルの対応する1つまたは複数の出力パラメータの型と同一でなければいけません。 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);
         

        ノート:元のターゲット・メソッド・ハンドルがあっても、結果のアダプタは可変性メソッド・ハンドルではありません。

        パラメータ:
        target - 引数を並べ替えたあとで呼び出すメソッド・ハンドル
        newType - 新しいメソッド・ハンドルの期待される型
        reorder - 並べ替えを制御するインデックス配列
        戻り値:
        未使用の引数を破棄し、ほかの引数の移動や複製を行ったあとでターゲットに委譲するメソッド・ハンドル
        例外:
        NullPointerException - いずれかの引数がnullの場合
        IllegalArgumentException - インデックス配列の長さがターゲットの引数長と等しくない場合、またはインデックス配列に、newTypeのパラメータの有効なインデックスでない要素が含まれている場合、またはtarget.type()newTypeの対応する2つのパラメータの型が同一でない場合
      • constant

        public static MethodHandle constant​(Class<?> type,
                                            Object value)
        要求された戻り値の型を持ち、呼び出されるたびに指定された定数値を返すメソッド・ハンドルを生成します。

        メソッド・ハンドルが返される前に、渡された値が要求された型に変換されます。 要求された型がプリミティブの場合はプリミティブ・ワイドニング変換が試みられ、それ以外の場合は参照変換が試みられます。

        返されるメソッド・ハンドルはidentity(type).bindTo(value)と同等です。

        パラメータ:
        type - 必要なメソッド・ハンドルの戻り値の型
        value - 返す値
        戻り値:
        指定された戻り値の型を持ち引数は一切取らない、常に指定された値を返すメソッド・ハンドル
        例外:
        NullPointerException - type引数がnullの場合
        ClassCastException - 要求された戻り値の型に値を変換できない場合
        IllegalArgumentException - 指定された型がvoid.classの場合
      • identity

        public static MethodHandle identity​(Class<?> type)
        呼出し時に唯一の引数の値を返すメソッド・ハンドルを生成します。
        パラメータ:
        type - 必要なメソッド・ハンドルの唯一のパラメータと戻り値の型
        戻り値:
        指定された型を受け入れて返す単項メソッド・ハンドル
        例外:
        NullPointerException - 引数がnullの場合
        IllegalArgumentException - 指定された型がvoid.classの場合
      • zero

        public static MethodHandle zero​(Class<?> type)
        リクエストされた戻り型の定数メソッド・ハンドルを生成します。このハンドルは、呼び出されるたびにその型のデフォルト値を返します。 結果の定数メソッド・ハンドルには副作用はありません。

        戻されるメソッド・ハンドルは、empty(methodType(type))と同等です。 また、explicitCastArgumentsnullをデフォルト値に変換するため、explicitCastArguments(constant(Object.class, null), methodType(type))と同等です。

        パラメータ:
        type - 目的のメソッド・ハンドルの予期される戻り型
        戻り値:
        引数をとらず、指定された型のデフォルト値を返す定数メソッド・ハンドル(型がvoidの場合はvoid)
        例外:
        NullPointerException - 引数がnullの場合
        導入されたバージョン:
        9
        関連項目:
        constant(java.lang.Class<?>, java.lang.Object), empty(java.lang.invoke.MethodType), explicitCastArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)
      • empty

        public static MethodHandle empty​(MethodType type)
        要求された型のメソッド・ハンドルを生成します。引数は無視され、何も実行されず、戻り型に応じて適切なデフォルトが返されます。 つまり、ゼロのプリミティブ値、nullまたはvoidを返します。

        戻されるメソッド・ハンドルは、dropArguments(zero(type.returnType()), 0, type.parameterList())と同等です。

        APIのノート:
        述語とターゲットを指定した場合、有用なif-thenコンストラクトをguardWithTest(pred, target, empty(target.type())として生成できます。
        パラメータ:
        type - 目的のメソッド・ハンドルの型
        戻り値:
        指定された型の定数メソッド・ハンドルで、指定された戻り型のデフォルト値を返します。
        例外:
        NullPointerException - 引数がnullの場合
        導入されたバージョン:
        9
        関連項目:
        zero(java.lang.Class<?>), constant(java.lang.Class<?>, java.lang.Object)
      • insertArguments

        public static MethodHandle insertArguments​(MethodHandle target,
                                                   int pos,
                                                   Object... values)
        ターゲット・メソッド・ハンドルの呼出しの前に、1つ以上のバインド引数をメソッド・ハンドルに提供します。 ターゲットの仮パラメータのうちで、バインド引数に対応しているものは、バインド・パラメータと呼ばれます。 バインド引数を保存した新しいメソッド・ハンドルを返します。 これは呼出し時に、すべての非バインド・パラメータに対する引数を受け取り、保存しておいた引数を対応するパラメータにバインドし、元のターゲットを呼び出します。

        新しいメソッド・ハンドルの型には、元のターゲットの型に含まれていたバインド・パラメータの型は含まれませんが、これは、新しいメソッド・ハンドルではもう、呼出し元がそれらの引数を指定する必要がないからです。

        指定された引数のオブジェクトはそれぞれ、対応するバインド・パラメータの型に一致する必要があります。 バインド・パラメータの型がプリミティブの場合、引数のオブジェクトはラッパーである必要があり、オブジェクトがアンボクシングされてプリミティブ値が生成されます。

        pos引数によってバインドするパラメータが選択されます。 その範囲は0 - N-L (両端を含む)です。ここで、Nはターゲット・メソッド・ハンドルの引数長、Lは値配列の長さです。

        ノート:元のターゲット・メソッド・ハンドルがあっても、結果のアダプタは可変性メソッド・ハンドルではありません。

        パラメータ:
        target - 引数を挿入したあとに呼び出すメソッド・ハンドル
        pos - 引数の挿入位置(先頭の場合はゼロ)
        values - 挿入する一連の引数
        戻り値:
        追加の引数を挿入してから元のメソッド・ハンドルを呼び出すメソッド・ハンドル
        例外:
        NullPointerException - ターゲットまたはvalues配列がnullの場合
        IllegalArgumentException - (@code pos)が0以下、N - Lより多く、Nがターゲット・メソッド・ハンドルの引数長さ、Lが値配列の長さである場合。
        ClassCastException - 引数が対応するバウンド・パラメータ・タイプと一致しない場合。
        関連項目:
        MethodHandle.bindTo(java.lang.Object)
      • dropArguments

        public static MethodHandle dropArguments​(MethodHandle target,
                                                 int pos,
                                                 List<Class<?>> valueTypes)
        いくつかのダミー引数を破棄してから指定された別のtargetメソッド・ハンドルを呼び出すメソッド・ハンドルを生成します。 新しいメソッド・ハンドルの型は、ターゲットの型とほぼ同じになりますが、指定された位置にダミー引数の型も含む点が異なります。

        pos引数の範囲は0 - N (Nはターゲットの引数の数)になります。 ダミー引数は、posが0の場合はターゲットの実際の引数の前に追加され、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 - 引数を除去したあとに呼び出すメソッド・ハンドル
        valueTypes - 除去する引数の型
        pos - 除去する最初の引数の位置(左端の場合は0)
        戻り値:
        指定された型の引数を除去してから元のメソッド・ハンドルを呼び出すメソッド・ハンドル
        例外:
        NullPointerException - ターゲットがnullの場合、またはvalueTypesリストまたはそのいずれかの要素がnullの場合
        IllegalArgumentException - valueTypesのいずれかの要素がvoid.classの場合、またはposが負であるかターゲットの引数の数より大きい場合、または新しいメソッド・ハンドルの型に含まれるパラメータの数が多すぎる場合
      • dropArguments

        public static MethodHandle dropArguments​(MethodHandle target,
                                                 int pos,
                                                 Class<?>... valueTypes)
        いくつかのダミー引数を破棄してから指定された別のtargetメソッド・ハンドルを呼び出すメソッド・ハンドルを生成します。 新しいメソッド・ハンドルの型は、ターゲットの型とほぼ同じになりますが、指定された位置にダミー引数の型も含む点が異なります。

        pos引数の範囲は0 - N (Nはターゲットの引数の数)になります。 ダミー引数は、posが0の場合はターゲットの実際の引数の前に追加され、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 - 引数を除去したあとに呼び出すメソッド・ハンドル
        valueTypes - 除去する引数の型
        pos - 除去する最初の引数の位置(左端の場合は0)
        戻り値:
        指定された型の引数を除去してから元のメソッド・ハンドルを呼び出すメソッド・ハンドル
        例外:
        NullPointerException - ターゲットがnullの場合、またはvalueTypes配列またはそのいずれかの要素がnullの場合
        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[])のように、一致しないパラメータ・タイプ(一致するサブリストの前または後)がターゲットの元のパラメータの対応する位置に挿入されます。

        結果のハンドルは、ターゲット・ハンドルと同じ戻り型を持ちます。

        より正式な用語では、次の2つのタイプ・リストがあるとします。

        • ターゲット・ハンドルには、パラメータ・タイプ・リストS..., M...があり、Sにはskipで示されるタイプと同じ数のタイプがあります。 M型は、指定された型リストnewTypesの一部と一致するはずの型です。
        • newTypesリストには、P..., M..., A...型が含まれ、posで示されるP内の型もすべて含まれます。 M型は、ターゲット・ハンドルのパラメータ・タイプ・リスト内のM型が一致することが想定されている型です。 Aの型は、一致するサブリストの後に検出される追加の型です。
        これらの仮定を考慮すると、dropArgumentsToMatchの起動の結果はパラメータ型リストS..., P..., M..., A...となり、P型とA型がdropArguments(MethodHandle, int, Class[])のように挿入されます。

        APIのノート:
        引数リストが「実質的に同一」(つまり、共通の接頭辞で同一)である2つのメソッド・ハンドルは、次のようにdropArgumentsToMatchへの2つのコールによって、共通型に相互に変換できます。
        
        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 - どちらかの引数がnullの場合
        IllegalArgumentException - newTypesのいずれかの要素がvoid.classの場合、またはskipが負またはターゲットのアリティより大きい場合、またはposが負またはnewTypesリスト・サイズより大きい場合、またはnewTypesposの位置にtargetのスキップされないパラメータ・タイプを含まない場合。
        導入されたバージョン:
        9
      • filterArguments

        public static MethodHandle filterArguments​(MethodHandle target,
                                                   int pos,
                                                   MethodHandle... filters)
        ターゲット・メソッド・ハンドルを適応させるため、その1つ以上の引数をそれぞれ固有の単項フィルタ関数を使って前処理したあと、前処理を行った各引数を対応するフィルタ関数の結果で置き換えてターゲットを呼び出します。

        前処理は、filters配列の要素として指定された1つ以上のメソッド・ハンドルによって実行されます。 フィルタ配列の最初の要素がターゲットのposの位置の引数に対応する、といった関係がその後も順に続きます。 フィルタ関数は、左から右の順序で起動されます。

        配列内のnull引数はアイデンティティ関数とみなされ、対応する引数は変更されないままになります。 (nullでない要素が配列内に1つも存在しない場合は、元のターゲットが返されます。) 各フィルタはアダプタの対応する引数に適用されます。

        フィルタFがターゲットのN番目の引数に適用される場合、Fは、ちょうど1つの引数を取るメソッド・ハンドルでなければいけません。 結果となる適応後のメソッド・ハンドル内では、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/pおよびB/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...);
         }
         

        ノート:元のターゲット・メソッド・ハンドルがあっても、結果のアダプタは可変性メソッド・ハンドルではありません。

        パラメータ:
        target - 引数をフィルタリングしたあとで呼び出すメソッド・ハンドル
        pos - フィルタリングする最初の引数の位置
        filters - フィルタリング対象の引数に対して最初に呼び出すメソッド・ハンドル
        戻り値:
        指定された引数フィルタリング・ロジックが組み込まれたメソッド・ハンドル
        例外:
        NullPointerException - ターゲットがnullの場合またはfilters配列がnullの場合
        IllegalArgumentException - filtersの非null要素がターゲットの対応する引数型と一致しない場合(前述の説明を参照)、またはpos+filters.lengthtarget.type().parameterCount()より大きい場合、または結果のメソッド・ハンドルの型のパラメータ数が多すぎる場合
      • collectArguments

        public static MethodHandle collectArguments​(MethodHandle target,
                                                    int pos,
                                                    MethodHandle filter)
        ターゲット・メソッド・ハンドルを、フィルタ(別のメソッド・ハンドル)でその引数のサブシーケンスを前処理することにより、適応させます。 前処理した引数は、フィルタ関数の結果(ある場合)によって置き換えられます。 すると、ターゲットは変更された(通常は短縮された)引数リストで呼び出されます。

        フィルタが値を返す場合、ターゲットはその値を位置pos(フィルタに渡されない引数の前または後)の引数として受け入れる必要があります。 フィルタがvoidを返す場合、ターゲットはフィルタに渡されないすべての引数を受け入れる必要があります。 引数は並べ替えられず、フィルタから返された結果によってアダプタにもともと渡された引数サブシーケンス全体が(順番に)置き換えられます。

        フィルタの引数型(ある場合)は、結果の適応済メソッド・ハンドル内で、ターゲットの0または1個の引数型(位置pos)を置き換えます。 フィルタの戻り型(ある場合)は、ターゲットの位置posの引数型と同じである必要があり、そのターゲット引数はフィルタの戻り値によって提供されます。

        どのような場合でも、posは0以上である必要があり、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"));
         

        結果のアダプタの疑似コードを次に示します。 このコードでは、Ttargetおよび結果のアダプタの戻り型を表します。 V/vは、filterの戻り型と値を表します。これは、Vvoidでないかぎり、それぞれtargetのシグネチャと引数にも含まれます。 A/aおよびC/cは、targetのシグネチャ内のコレクション位置posの前後のパラメータ・タイプおよび値を表します。 また、結果として得られるアダプタのシグネチャおよび引数も示され、filter (存在する場合)へのパラメータ・タイプおよび引数を表すB/bを囲みます。

        
         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)は、次のような個別のステップで、まず影響を受ける引数を折りたたんでから(fold)破棄(drop)するものと同等です。

        
         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が1つの引数を消費して非void結果を生成する場合は、collectArguments(mh, N, coll)filterArguments(mh, N, coll)と同等です。 他の等価性も可能ですが、引数順列が必要です。

        ノート:元のターゲット・メソッド・ハンドルがあっても、結果のアダプタは可変性メソッド・ハンドルではありません。

        パラメータ:
        target - 引数サブシーケンスをフィルタした後に呼び出すメソッド・ハンドル
        pos - フィルタに渡す最初のアダプタ引数、またはフィルタの結果を受け取るターゲット引数、あるいはその両方の位置
        filter - 引数サブシーケンスで呼び出すメソッド・ハンドル
        戻り値:
        指定された引数サブシーケンス・フィルタリング・ロジックを組み込んだメソッド・ハンドル
        例外:
        NullPointerException - どちらかの引数がnullの場合
        IllegalArgumentException - filterの戻り型が非voidでターゲットのpos引数と同じでない場合、またはposが0からターゲットの引数カウントの間(含む)にない場合、または結果のメソッド・ハンドルの型のパラメータ数が多すぎる場合
        関連項目:
        foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle)filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...)filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle)
      • 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の結果タイプと値、filterの結果タイプ、Vおよび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);
         }
         

        ノート:元のターゲット・メソッド・ハンドルがあっても、結果のアダプタは可変性メソッド・ハンドルではありません。

        パラメータ:
        target - 戻り値をフィルタリングする前に呼び出すメソッド・ハンドル
        filter - 戻り値に対して呼び出すメソッド・ハンドル
        戻り値:
        指定された戻り値フィルタリング・ロジックが組み込まれたメソッド・ハンドル
        例外:
        NullPointerException - どちらかの引数がnullの場合
        IllegalArgumentException - 前述のようにfilterの引数リストがターゲットの戻り値の型と一致しない場合
      • foldArguments

        public static MethodHandle foldArguments​(MethodHandle target,
                                                 MethodHandle combiner)
        ターゲット・メソッド・ハンドルを適応させるため、その引数のいくつかを前処理したあと、前処理の結果を元の一連の引数内に挿入してターゲットを呼び出します。

        前処理は、2番目のメソッド・ハンドルである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"));
         

        結果のアダプタの疑似コードを次に示します。 コードでは、Ttargetおよび結果のアダプタの結果タイプを表します。 V/vは、折りたたみ位置より前にあるtargetのパラメータおよび引数の型と値を表し、Vcombinerの結果型でもあります。 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...);
         }
         

        ノート:元のターゲット・メソッド・ハンドルがあっても、結果のアダプタは可変性メソッド・ハンドルではありません。

        パラメータ:
        target - 引数を結合したあとで呼び出すメソッド・ハンドル
        combiner - 入力引数に対して最初に呼び出すメソッド・ハンドル
        戻り値:
        指定された引数フォールディング・ロジックが組み込まれたメソッド・ハンドル
        例外:
        NullPointerException - どちらかの引数がnullの場合
        IllegalArgumentException - combinerの戻り値の型がvoidでなく、ターゲットの最初の引数の型と同じでない場合、あるいはターゲットの最初の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"));
         

        結果のアダプタの疑似コードを次に示します。 コードでは、Ttargetおよび結果のアダプタの結果タイプを表します。 V/vは、折りたたみ位置より前にあるtargetのパラメータおよび引数の型と値を表し、Vcombinerの結果型でもあります。 A/aは、折りたたみ位置にあるNパラメータおよび引数の型と値を示します。 Z/zおよびB/bは、targetパラメータのタイプと値、およびposで始まる折りたたまれたパラメータと引数の前後の引数の値を表します。

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

        ノート:元のターゲット・メソッド・ハンドルがあっても、結果のアダプタは可変性メソッド・ハンドルではありません。

        パラメータ:
        target - 引数を結合したあとで呼び出すメソッド・ハンドル
        pos - 折りたたみを開始する位置、および折りたたみ結果を挿入する位置。これが 0の場合、効果はfoldArguments(MethodHandle, MethodHandle)の場合と同じです。
        combiner - 入力引数に対して最初に呼び出すメソッド・ハンドル
        戻り値:
        指定された引数フォールディング・ロジックが組み込まれたメソッド・ハンドル
        例外:
        NullPointerException - どちらかの引数がnullの場合
        IllegalArgumentException - 次の2つの条件のいずれかが保持されている場合: (1) combinerの戻り型が非voidで、ターゲット・シグネチャの位置posの引数型と同じではありません。(2)ターゲット・シグネチャの位置posN引数型(combinerの戻り型と一致するものをスキップ)は、引数型combinerと同一ではありません。
        導入されたバージョン:
        9
        関連項目:
        foldArguments(MethodHandle, MethodHandle)
      • guardWithTest

        public static MethodHandle guardWithTest​(MethodHandle test,
                                                 MethodHandle target,
                                                 MethodHandle fallback)
        テスト(boolean値のメソッド・ハンドル)で保護することでターゲット・メソッド・ハンドルを適応させるメソッド・ハンドルを作成します。 保護に失敗した場合は、代わりにフォール・バック・ハンドルが呼び出されます。 テストの戻り値の型がbooleanでなければいけない点と、テストの引数の数がほかの2つのメソッド・ハンドルより少なくてもかまわないという点を除き、3つのメソッド・ハンドルの対応する引数と戻り値の型はすべて同じである必要があります。

        結果のアダプタの疑似コードを次に示します。 このコードでは、Tは、関連する3つのハンドルの均一な結果タイプを表します。A/atestによって消費されるtargetパラメータおよび引数のタイプと値、およびB/btestによって消費されないtargetパラメータおよび引数のタイプと値。

        
         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 - いずれかの引数がnullの場合
        IllegalArgumentException - testがbooleanを返さない場合、または(testの戻り値の型を変更してターゲットの型と一致させても) 3つのすべてのメソッド型が一致しない場合
      • catchException

        public static MethodHandle catchException​(MethodHandle target,
                                                  Class<? extends Throwable> exType,
                                                  MethodHandle handler)
        ターゲットのメソッド・ハンドルを例外ハンドラの内部で実行することによって、このターゲットを適応させるメソッド・ハンドルを作成します。 ターゲットが通常どおり値を返した場合、アダプタはその値を返します。 指定された型に一致する例外がスローされた場合、代わりにその例外と元の引数を指定してフォール・バック・ハンドルが呼び出されます。

        ターゲットとハンドラの対応する引数と戻り値の型は基本的に同じである必要がありますが、ハンドラでは(guardWithTestの述語と同様に)末尾の複数の引数を省略できます。 さらにハンドラは、exTypeまたはスーパー・タイプの先頭のパラメータを追加で1つ持つ必要があります。

        結果のアダプタの疑似コードを次に示します。 このコードでは、Tは、targetおよびhandlerの戻り型を表し、それに応じて結果のアダプタの戻り型を表します。A/aは、handlerによって消費される結果のハンドルに対する引数の型と値、および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 - いずれかの引数がnullの場合
        IllegalArgumentException - handlerが指定された例外の型を受け入れない場合、またはメソッド・ハンドルの型に含まれる戻り値の型と対応するパラメータが一致しない場合
        関連項目:
        tryFinally(MethodHandle, MethodHandle)
      • throwException

        public static MethodHandle throwException​(Class<?> returnType,
                                                  Class<? extends Throwable> exType)
        指定されたexTypeの例外をスローするメソッド・ハンドルを生成します。 メソッド・ハンドルは、exTypeの単一の引数を受け入れ、それを即時に例外としてスローします。 メソッド型では形式上、returnTypeの戻り値が指定されます。 戻り値の型は、どのようなものでもかまいません。メソッド・ハンドルが通常どおりに戻ることは決してないので、メソッド・ハンドルの動作には何の影響もありません。
        パラメータ:
        returnType - 期待するメソッド・ハンドルの戻り型
        exType - 期待するメソッド・ハンドルのパラメータ型
        戻り値:
        指定された例外をスローできるメソッド・ハンドル
        例外:
        NullPointerException - どちらかの引数がnullの場合
      • loop

        public static MethodHandle loop​(MethodHandle[]... clauses)
        反復ごとに更新およびチェックされる複数のループ変数を含むループを表すメソッド・ハンドルを構築します。 述語のいずれかが原因でループが終了すると、対応するファイナライザが実行され、ループの結果(結果のハンドルの戻り値)が出力されます。

        直感的に、すべてのループは1つ以上の句によって形成され、それぞれがローカルのイテレーション変数またはループ・イグジット(あるいはその両方)を指定します。 ループの各反復は、各句を順番に実行します。 句はオプションで反復変数を更新でき、オプションでテストおよび条件付きループの終了を実行することもできます。 このロジックをメソッド・ハンドルで表すために、各句では最大4つの独立したアクションを指定します。

        • init:ループが実行される前に、V型の反復変数vを初期化します。
        • ステップ:句が実行されると、反復変数vの更新ステップが実行されます。
        • pred:句が実行されると、forループの終了をテストする述語が実行されます。
        • fini:句によってループが終了した場合、ファイナライザはループの戻り値を計算します。
        すべての反復変数型の完全な順序は、句の順序で(V...)として表記されます。 値自体は(v...)です。 パラメータ・リストについては、通常、型を参照しますが、一部のコンテキスト(実行の説明)では、リストは実際の値になります。

        これらの句の一部の部分は、特定のルールに従って省略でき、この場合、有効なデフォルトの動作が提供されます。 詳細は、次を参照してください。

        すべての場所でオプションのパラメータ:各句関数は許可されますが、反復変数vごとにパラメータを受け入れる必要はありません。 ただし、initファンクションの実行時にこれらの値がまだ計算されないため、initファンクションではvパラメータを使用できません。 どの句関数も、取得する権利があるパラメータの末尾のサブシーケンスを省略できます。 実際には、どの句関数も引数を取らないことがあります。

        ループ・パラメータ:句ファンクションは、付与されているすべての反復変数値を使用できます。この場合、後続のパラメータも多く取ることができます。 このような余分な値はループ・パラメータと呼ばれ、その型と値は(A...)および(a...)として表記されます。 これらは、ループが実行されるたびに指定される、結果のループ・ハンドルのパラメータになります。 (init関数は反復変数vを受け入れないため、init関数のパラメータは自動的にループ・パラメータaになります。) 反復変数と同様に、句関数は許可されますが、ループ・パラメータを受け入れる必要はありません。 これらのループ・パラメータは、ループ全体で表示されるループ不変値として機能します。

        すべての場所で表示されるパラメータ:各非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*)です。

        句構造のチェック:句のセットを指定した場合、ループのすべての部分を接続するために多数のチェックおよび調整が実行されます。 これらは、次のステップで詳細に説明されています。 これらのステップでは、必要な制約がループ・コンビネータへの入力によって満たされない場合にIllegalArgumentExceptionがスローされる場所に対応する「must」という単語が出現します。

        実質的には同一順序: パラメータ・リストAは、ABが同一の場合、またはAが短く、適切な接頭辞Bと同一の場合に、別のパラメータ・リストB実質的には同一として定義されます。 順序付けされていない一連のパラメータ・リストについて言えば、セットに最長のリストが含まれていて、セットのすべてのメンバーが実質的にその最長のリストと同一である場合、セット全体は「実質的に同一」であるといえます。 たとえば、(V*)という形式の型シーケンスのセットは事実上同一であり、(V... A*)という形式のシーケンスが追加される場合は同じことが当てはまります。

        ステップ0: 条項構造を決定します。

        1. 句配列(MethodHandle[][]型)は、null以外で、少なくとも1つの要素が含まれている必要があります。
        2. 句配列には、nullまたはサブ配列を4要素より長く含めることはできません。
        3. 4つより短い句は、null要素によって4つまでの長さにパディングされたかのように処理されます。 パディングは、配列に要素を追加することによって行われます。
        4. すべてのnullを含む句は無視されます。
        5. 各句は、「init」、「step」、「pred」、および「fini」と呼ばれる4組の関数として扱われます。

        ステップ1A: 反復変数型(V...)を決定します。

        1. 各句の反復変数の型は、句のinitおよびstep戻り型を使用して決定されます。
        2. 両方の関数を省略した場合、対応する句の反復変数はありません(voidがそれを示す型として使用されます)。 いずれかを省略すると、もう一方の戻り型によって、句の反復変数型が定義されます。 両方が指定されている場合は、共通戻り型(同一である必要があります)によって、句の反復変数型が定義されます。
        3. voidのすべての出現を省略して、戻り型のリストを(句の順序で)作成します。
        4. この型のリストは、反復変数型((V...))と呼ばれます。

        ステップ1B: ループ・パラメータ(A...)を決定します。

        • init関数のパラメータ・リスト((A*)の形式)を調べ、収集します。
        • 反復変数型を削除した後、ステップ、predおよびfiniパラメータ・リストの接尾辞を調べて収集します。 ((V... A*)という形式である必要があります。(A*)部分のみを収集します。)
        • すべての反復変数型で始まらないステップ、predおよびfiniパラメータ・リストから接尾辞を収集しないでください。 (これらのタイプは、すべての条項関数タイプとともにステップ2でチェックインされます。)
        • 省略された句関数は無視されます。 (同様に、パラメータ・リストは空であるとみなされます。)
        • 収集されたすべてのパラメータ・リストは、事実上同一である必要があります。
        • 最長のパラメータ・リスト(必ず一意)は、外部パラメータ・リスト((A...))と呼ばれます。
        • そのようなパラメータ・リストがない場合、外部パラメータ・リストは空の順序とみなされます。
        • 反復変数型とそれに続く外部パラメータ型で構成される結合リストは、内部パラメータ・リストと呼ばれます。

        ステップ1C: ループ戻り型を決定します。

        1. 省略されたfini関数を無視して、fini関数の戻り型を調べます。
        2. fini関数がない場合、ループの戻り型はvoidです。
        3. それ以外の場合、fini関数の一般的な戻り型R (戻り型は同一である必要があります)によって、ループ戻り型が定義されます。

        ステップ1D: 他のタイプを確認します。

        1. 少なくとも1つの非省略事前関数が必要です。
        2. 省略されていないすべてのpred関数は、boolean戻り型を持つ必要があります。

        ステップ2: パラメータ・リストを決定します。

        1. 結果のループ・ハンドルのパラメータ・リストは、外部パラメータ・リスト(A...)になります。
        2. init関数のパラメータ・リストは、外部パラメータ・リストに調整されます。 (パラメータ・リストはすでにこのリストと実質的に同一であることに注意してください。)
        3. 省略なし、init以外のすべての(step、predおよびfini)関数のパラメータ・リストは、内部パラメータ・リスト(V... A...)と実質的に同一である必要があります。

        ステップ3: 省略された関数を入力します。

        1. init関数を省略する場合は、句の反復変数型にデフォルト値を使用します。
        2. ステップ関数を省略した場合は、句の反復変数型のアイデンティティ関数を使用します。前述の句のvoid以外の反復変数のアイデンティティ関数パラメータの前に、削除された引数パラメータを挿入します。 (これにより、ループ変数がローカル・ループ不変条件に変換されます。)
        3. pred関数を省略した場合は、定数true関数を使用します。 (これにより、この句に関するかぎり、ループが進行し続けます。 このような場合、対応するfini関数にアクセスできないことに注意してください。)
        4. fini関数を省略する場合は、ループ戻り値の型にデフォルト値を使用します。

        ステップ4: 欠落しているパラメータ・タイプを入力します。

        1. この時点で、すべてのinit関数のパラメータ・リストは外部パラメータ・リスト(A...)と実質的に同じですが、リストによっては短くなる場合があります。 短いパラメータ・リストを持つすべてのinit関数について、リストの末尾をパッド・アウトします。
        2. この時点で、すべての非initファンクション・パラメータ・リストは、内部パラメータ・リスト(V... A...)と実質的に同じですが、リストによっては短くなる場合があります。 短いパラメータ・リストを持つinit以外の関数ごとに、リストの末尾をパッド・アウトします。
        3. 引数リストは、未使用の末尾の引数を削除することでパディングアウトされます。

        最終観察。

        1. これらのステップの後、省略された関数と引数を指定することで、すべての句が調整されました。
        2. すべてのinit関数には共通のパラメータ型リスト(A...)があり、最終的なループ・ハンドルも持ちます。
        3. すべてのfini関数には共通の戻り型Rがあり、最終的なループ・ハンドルも持ちます。
        4. すべての非init関数には、共通のパラメータ型リスト(V... A...)があり、(void以外の)反復変数Vの後にループ・パラメータが続きます。
        5. init関数とステップ関数の各ペアは、戻り型Vで一致します。
        6. 各非init関数は、すべての反復変数の現在の値(v...)を監視できます。
        7. すべてのファンクションは、すべてのループ・パラメータの着信値(a...)を監視できます。

        Example. 前述のステップ1Aの結果として、loopコンビネータには次のプロパティがあります。

        • N句を指定すると、Cn = {"null", Sn, Pn}n = 1..Nが付けられます。
        • 述語ハンドルPnnullであるか、パラメータがないとします。 (1つのPnのみがnull以外である必要があります。)
        • ステップ・ハンドルSnに、定数X>=Nのシグネチャ(B1..BX)Rnがあるとします。
        • Qがvoid以外の型Rnの数で、(V1...VQ)がそれらの型の順序であるとします。
        • n = 1..min(X,Q)Vn == Bnである必要があります。
        • パラメータ型Vnは、ループ・ローカル状態要素(V...)として解釈されます。
        • 残りの型BQ+1..BX (Q<Xの場合)は、結果のループ・ハンドルのパラメータ型(A...)を決定します。
        この例では、ループ・ハンドル・パラメータ(A...)がステップ関数から導出されています。これは、ほとんどのループ計算がステップで実行される場合に自然です。 一部のループでは、計算の負担がpred関数で最も重いため、pred関数がループ・パラメータ値を受け入れる必要がある場合があります。 複雑な終了ロジックを持つループの場合、fini関数はループ・パラメータを受け入れる必要があり、同様に、init関数に追加のパラメータを必要とする複雑なエントリ・ロジックを持つループの場合も同様です。 このような理由から、これらのパラメータを決定するためのルールは、すべての条項部分にわたって可能なかぎり対称的です。 一般に、ループ・パラメータはループ全体にわたって共通の不変値として機能し、反復変数は共通のバリアント値として機能し、(ステップ関数がない場合は)内部ループ不変時間として機能します。

        ループの実行。

        1. ループがコールされると、ループ入力値はローカルに保存され、すべての句関数に渡されます。 これらのローカルはループ不変です。
        2. 各init関数は、句の順序(外部引数(a...)を渡す)で実行され、void以外の値は(反復変数(v...)として)ローカルに保存されます。 これらのローカルは、ループが変化します(前述のように、それらのステップがアイデンティティー関数として動作しないかぎり)。
        3. すべてのファンクション実行(initファンクションを除く)は、void以外の反復値(v...)(句の順序)で構成される内部パラメータ・リストに渡され、ループは(a...)(引数の順序)を入力します。
        4. その後、predファンクションがfalseを返すまで、ステップおよびpredファンクションが句の順序(predの前にステップ)で実行されます。
        5. ステップ関数コールからのvoid以外の結果は、ループ変数の順序(v...)内の対応する値を更新するために使用されます。 更新された値は、後続のすべての関数コールにただちに表示されます。
        6. pred関数がfalseを返す場合、対応するfini関数が呼び出され、結果の値(R型)がループ全体から返されます。
        7. すべてのpred関数が常にtrueを返す場合、fini関数は呼び出されず、ループは例外をスローすること以外は終了できません。

        使用上のヒント。

        • 各ステップ関数は、すべてのループ変数の現在の値を受け取りますが、ステップ関数は、その変数の現在の値のみを監視する必要がある場合があります。 その場合、ステップ関数は明示的に前述のすべてのループ変数を削除する必要があります。 これには、dropArguments(step, 0, V0.class, ...)のような式で型を記述する必要があります。
        • ループ変数は変更する必要はなく、ループ不変です。 句は、ステップ、predまたはfini関数なしで適切なinit関数によってループ不変条件を作成できます。 これは、受信ループ引数を隣接するループ変数のステップまたは前関数にワイヤリングする場合に便利です。
        • 一部の句関数がインスタンス上の仮想メソッドである場合、インスタンス自体は、new MethodHandle[]{identity(ObjType.class)}のような初期句を使用して、初期不変ループ変数に便利に配置できます。 その場合、インスタンス参照は最初の反復変数値になり、仮想メソッドはすべてその値に一致する先頭のインスタンス参照をとるため、句の部分として簡単に使用できます。

        結果のループ・ハンドルの疑似コードを次に示します。 前述のように、Vおよびvはループ変数の型と値を表し、Aおよびaはループ全体に渡される引数を表し、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(MethodHandle, MethodHandle, MethodHandle), doWhileLoop(MethodHandle, MethodHandle, MethodHandle), countedLoop(MethodHandle, MethodHandle, MethodHandle), iteratedLoop(MethodHandle, MethodHandle, MethodHandle)
      • 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という名前に割り当て、voidVがパラメータ・リストから静かに削除され、(A...)Vのままであることを理解して、(V A...)Vを記述します。)
        • 本文のパラメータ・リスト(V A...)は、内部パラメータ・リストと呼ばれます。 他のループ部分のパラメータ・リストを制約します。
        • 反復変数型Vが内部パラメータ・リストから削除されると、結果の短いリスト(A...)外部パラメータ・リストと呼ばれます。
        • 本体戻り型V(void以外の場合)は、ループの追加状態変数の型を決定します。 本体は、この型Vの値を受け入れて戻す必要があります。
        • initnull以外の場合、戻り型は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 - predまたはbodynullの場合。
        導入されたバージョン:
        9
        関連項目:
        loop(MethodHandle[][]), doWhileLoop(MethodHandle, MethodHandle, MethodHandle)
      • 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という名前に割り当て、voidVがパラメータ・リストから静かに削除され、(A...)Vのままであることを理解して、(V A...)Vを記述します。)
        • 本文のパラメータ・リスト(V A...)は、内部パラメータ・リストと呼ばれます。 他のループ部分のパラメータ・リストを制約します。
        • 反復変数型Vが内部パラメータ・リストから削除されると、結果の短いリスト(A...)外部パラメータ・リストと呼ばれます。
        • 本体戻り型V(void以外の場合)は、ループの追加状態変数の型を決定します。 本体は、この型Vの値を受け入れて戻す必要があります。
        • initnull以外の場合、戻り型は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 - predまたはbodynullの場合。
        導入されたバージョン:
        9
        関連項目:
        loop(MethodHandle[][]), whileLoop(MethodHandle, MethodHandle, MethodHandle)
      • countedLoop

        public static MethodHandle countedLoop​(MethodHandle iterations,
                                               MethodHandle init,
                                               MethodHandle body)
        指定した数の反復を実行するループを構築します。 これは、汎用ループ・コンビネータの便利なラッパーです。

        反復回数は、iterationsハンドルの評価結果によって決まります。 ループ・カウンタiは、int型の余分なループ反復変数です。 これは、反復ごとに0に初期化され、1ずつ増分されます。

        bodyハンドルがvoid以外の型Vを返す場合、その型の先行ループ反復変数も存在します。 この変数は、オプションのinitハンドルを使用して、またはV型のデフォルト値(そのハンドルがnullの場合)を使用して初期化されます。

        反復ごとに、反復変数がbodyハンドルの呼出しに渡されます。 (V型の)本体から戻されるvoid以外の値によって、先頭の反復変数が更新されます。 ループ・ハンドル実行の結果は、その変数の最後のV値(V変数がない場合はvoid)になります。

        引数ハンドルには、次のルールが適用されます。

        • iterationsハンドルはnullではなく、パラメータ・タイプ・リストのIと呼ばれるint型を返す必要があります。
        • bodyハンドルは、nullではなく、(V I A...)Vの形式(Vは非void、それ以外は(I A...)void)である必要があります。 (voidの場合、void型をVという名前に割り当て、voidVがパラメータ・リストから静かに削除され、(I A...)Vのままであることを理解して、(V I A...)Vを記述します。)
        • 本体のパラメータ・リスト(V I A...)は、内部パラメータ・リストと呼ばれる型のリストに寄与します。 他のループ部分のパラメータ・リストを制約します。
        • 特殊なケースとして、ボディがVおよびI型のみに寄与し、A型が追加されていない場合、内部パラメータ・リストはiterationsハンドルの引数型A...によって拡張されます。
        • 反復変数型(V I)が内部パラメータ・リストから削除されると、結果の短いリスト(A...)外部パラメータ・リストと呼ばれます。
        • 本体戻り型V(void以外の場合)は、ループの追加状態変数の型を決定します。 本体は、先頭のパラメータを受け入れ、この型Vの値を返す必要があります。
        • initnull以外の場合、戻り型はVである必要があります。 そのパラメータ・リスト(一部のフォーム(A*))は、外部パラメータ・リスト(A...)実質的に同一である必要があります。
        • initnullの場合、ループ変数はそのデフォルト値に初期化されます。
        • iterationsのパラメータ・リスト(なんらかの形式の(A*))は、外部パラメータ・リスト(A...)と実質的に同一である必要があります。

        結果のループ・ハンドルの結果タイプおよびパラメータ・シグネチャは、次のように決定されます。

        • ループ・ハンドルの結果型は、本体の結果型Vです。
        • ループ・ハンドルのパラメータ・タイプは、外部パラメータ・リストの(A...)型です。

        結果のループ・ハンドルの疑似コードを次に示します。 このコードでは、V/vは2番目のループ変数の型/値とループの結果型を表し、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!"));
         
        、最も単純なbodyメソッド・タイプを使用し、反復回数をループ呼出しに渡す例:
        
         // 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ではない場合があります。 標準ケースのループ・パラメータおよび結果タイプを制御します(詳細は前述を参照)。 独自の戻り型(void以外の場合)とintパラメータ(カウンタの場合)を受け入れ、任意の数の追加型を受け入れることができます。 その他の制約については、上記を参照してください。
        戻り値:
        ループを表すメソッド・ハンドル。
        例外:
        NullPointerException - iterationsハンドルまたはbodyハンドルのいずれかがnullの場合。
        IllegalArgumentException - 引数が前述のルールに違反している場合。
        導入されたバージョン:
        9
        関連項目:
        countedLoop(MethodHandle, MethodHandle, MethodHandle, MethodHandle)
      • countedLoop

        public static MethodHandle countedLoop​(MethodHandle start,
                                               MethodHandle end,
                                               MethodHandle init,
                                               MethodHandle body)
        数値の範囲をカウントするループを構築します。 これは、汎用ループ・コンビネータの便利なラッパーです。

        ループ・カウンタiは、int型のループ反復変数です。 startおよびendハンドルは、ループ・カウンタの開始値(包含値)および終了値(除外値)を決定します。 ループ・カウンタは、startハンドルの評価から戻されたint値に初期化され、ステップ幅1のendから戻された値に(排他的に)実行されます。

        bodyハンドルがvoid以外の型Vを返す場合、その型の先行ループ反復変数も存在します。 この変数は、オプションのinitハンドルを使用して、またはV型のデフォルト値(そのハンドルがnullの場合)を使用して初期化されます。

        反復ごとに、反復変数がbodyハンドルの呼出しに渡されます。 (V型の)本体から戻されるvoid以外の値によって、先頭の反復変数が更新されます。 ループ・ハンドル実行の結果は、その変数の最後のV値(V変数がない場合はvoid)になります。

        引数ハンドルには、次のルールが適用されます。

        • startハンドルおよびendハンドルは、nullではなく、パラメータ型リストのIと呼ばれる共通型intを返す必要があります。
        • bodyハンドルは、nullではなく、(V I A...)Vの形式(Vは非void、それ以外は(I A...)void)である必要があります。 (voidの場合、void型をVという名前に割り当て、voidVがパラメータ・リストから静かに削除され、(I A...)Vのままであることを理解して、(V I A...)Vを記述します。)
        • 本体のパラメータ・リスト(V I A...)は、内部パラメータ・リストと呼ばれる型のリストに寄与します。 他のループ部分のパラメータ・リストを制約します。
        • 特殊なケースとして、ボディがVおよびI型のみに寄与し、A型が追加されていない場合、内部パラメータ・リストはendハンドルの引数型A...によって拡張されます。
        • 反復変数型(V I)が内部パラメータ・リストから削除されると、結果の短いリスト(A...)外部パラメータ・リストと呼ばれます。
        • 本体戻り型V(void以外の場合)は、ループの追加状態変数の型を決定します。 本体は、先頭のパラメータを受け入れ、この型Vの値を返す必要があります。
        • initnull以外の場合、戻り型はVである必要があります。 そのパラメータ・リスト(一部のフォーム(A*))は、外部パラメータ・リスト(A...)実質的に同一である必要があります。
        • initnullの場合、ループ変数はそのデフォルト値に初期化されます。
        • startのパラメータ・リスト(なんらかの形式の(A*))は、外部パラメータ・リスト(A...)と実質的に同一である必要があります。
        • 同様に、endのパラメータ・リストは、外部パラメータ・リストと実質的に同一である必要があります。

        結果のループ・ハンドルの結果タイプおよびパラメータ・シグネチャは、次のように決定されます。

        • ループ・ハンドルの結果型は、本体の結果型Vです。
        • ループ・ハンドルのパラメータ・タイプは、外部パラメータ・リストの(A...)型です。

        結果のループ・ハンドルの疑似コードを次に示します。 このコードでは、V/vは2番目のループ変数の型/値とループの結果型を表し、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ではない場合があります。 標準ケースのループ・パラメータおよび結果タイプを制御します(詳細は前述を参照)。 独自の戻り型(void以外の場合)とintパラメータ(カウンタの場合)を受け入れ、任意の数の追加型を受け入れることができます。 その他の制約については、上記を参照してください。
        戻り値:
        ループを表すメソッド・ハンドル。
        例外:
        NullPointerException - startendまたはbodyハンドルのいずれかがnullの場合。
        IllegalArgumentException - 引数が前述のルールに違反している場合。
        導入されたバージョン:
        9
        関連項目:
        countedLoop(MethodHandle, MethodHandle, MethodHandle)
      • iteratedLoop

        public static MethodHandle iteratedLoop​(MethodHandle iterator,
                                                MethodHandle init,
                                                MethodHandle body)
        Iterator<T>によって生成される値を範囲とするループを構築します。 これは、汎用ループ・コンビネータの便利なラッパーです。

        イテレータ自体は、iteratorハンドルの評価によって決定されます。 生成される各値は、T型のループ反復変数に格納されます。

        bodyハンドルがvoid以外の型Vを返す場合、その型の先行ループ反復変数も存在します。 この変数は、オプションのinitハンドルを使用して、またはV型のデフォルト値(そのハンドルがnullの場合)を使用して初期化されます。

        反復ごとに、反復変数がbodyハンドルの呼出しに渡されます。 (V型の)本体から戻されるvoid以外の値によって、先頭の反復変数が更新されます。 ループ・ハンドル実行の結果は、その変数の最後のV値(V変数がない場合はvoid)になります。

        引数ハンドルには、次のルールが適用されます。

        • bodyハンドルは、nullではなく、(V T A...)Vの形式(Vは非void、それ以外は(T A...)void)である必要があります。 (voidの場合、void型をVという名前に割り当て、voidVがパラメータ・リストから静かに削除され、(T A...)Vのままであることを理解して、(V T A...)Vを記述します。)
        • 本体のパラメータ・リスト(V T A...)は、内部パラメータ・リストと呼ばれる型のリストに寄与します。 他のループ部分のパラメータ・リストを制約します。
        • 特殊なケースとして、本文がVおよびT型のみに寄与し、A型を追加しない場合、内部パラメータ・リストはiteratorハンドルの引数型A...によって拡張されます。nullの場合、単一型Iterableが追加され、A...リストを構成します。
        • 反復変数型(V T)が内部パラメータ・リストから削除されると、結果の短いリスト(A...)外部パラメータ・リストと呼ばれます。
        • 本体戻り型V(void以外の場合)は、ループの追加状態変数の型を決定します。 本体は、先頭のパラメータを受け入れ、この型Vの値を返す必要があります。
        • initnull以外の場合、戻り型はVである必要があります。 そのパラメータ・リスト(一部のフォーム(A*))は、外部パラメータ・リスト(A...)実質的に同一である必要があります。
        • initnullの場合、ループ変数はそのデフォルト値に初期化されます。
        • iteratorハンドルがnull以外の場合は、戻り型java.util.Iteratorまたはそのサブタイプが必要です。 ループの実行時に生成されるイテレータは、T型に変換できる値を生成すると想定されます。
        • (なんらかの形式の(A*)の)null以外のiteratorのパラメータ・リストは、外部パラメータ・リスト(A...)と実質的に同一である必要があります。
        • iteratornullの場合、デフォルトでIterable.iterator()のように動作するメソッド・ハンドルになります。 その場合、内部パラメータ・リスト(V T A...)は、少なくとも1つのA型を持つ必要があり、デフォルトのイテレータ・ハンドル・パラメータは、asType変換メソッドの場合と同様に、先頭のA型を受け入れるように調整されます。 先頭のA型は、Iterableまたはそのサブタイプである必要があります。 この変換ステップは、ループ構築時に実行され、WrongMethodTypeExceptionをスローしないでください。

        Tは、プリミティブまたは参照のいずれかです。 Iterator<T>型はメソッド・ハンドル表現でRAW型Iteratorに消去されるため、iteratedLoopコンビネータは、asType変換メソッドの場合と同様に、bodyの先頭の引数型をObjectに調整します。 したがって、誤った型のイテレータがループの実行時に表示される場合、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ではない場合があります。 標準ケースのループ・パラメータおよび結果タイプを制御します(詳細は前述を参照)。 独自の戻り型(void以外の場合)とTパラメータ(反復値の場合)を受け入れ、任意の数の追加型を受け入れることができます。 その他の制約については、上記を参照してください。
        戻り値:
        反復ループ機能を具体化するメソッド・ハンドルです。
        例外:
        NullPointerException - bodyハンドルがnullの場合。
        IllegalArgumentException - 引数が前述の要件に違反している場合。
        導入されたバージョン:
        9
      • tryFinally

        public static MethodHandle tryFinally​(MethodHandle target,
                                              MethodHandle cleanup)
        try-finallyブロックにラップして、targetメソッド・ハンドルを適応させるメソッド・ハンドルを作成します。 別のメソッド・ハンドルcleanupは、finallyブロックの機能を表します。 targetハンドルの実行中にスローされた例外は、cleanupハンドルに渡されます。 cleanupハンドルが最初に例外をスローしないかぎり、例外は再スローされます。 cleanupハンドルの実行から戻される値は、try-finallyハンドルの実行結果になります。

        cleanupハンドルには、1つまたは2つの先行引数が渡されます。 1つ目は、targetハンドルの実行中にスローされた例外、または例外がスローされなかった場合はnullです。 2つ目は、targetハンドルの実行結果です。例外がスローされた場合、必要な型のnull、0またはfalse値がプレースホルダとして指定されます。 targetハンドルにvoid戻り型がある場合、2番目の引数は存在しません。 (引数型の変換を除き、コンビネータは、nullまたはゼロ値を挿入するのではなく、対応するパラドックス引数を省略することで、パラメータ・リストのvoid値を表します。)

        targetハンドルとcleanupハンドルは、対応する引数と戻り型が同じである必要があります。ただし、cleanupハンドルは後続の引数を省略できます。 また、cleanupハンドルには、1つまたは2つの先行パラメータが必要です。

        • Throwabletargetハンドルによってスローされた例外(ある場合)を継承します。
        • targetおよびcleanupの戻り型と同じ型のパラメータで、targetハンドルの実行の結果が出力されます。 targetvoidを返す場合、このパラメータは存在しません。

        結果のアダプタの疑似コードは次のようになります。 このコードでは、Vtry/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を宣言することをお薦めします。 これにより、targetがスローする例外を除き、常にcleanupが起動されるようになります。 絞込みタイプを宣言すると、try-finallyによってスローされた例外のタイプがtargetによってスローされた例外のタイプがcleanupの最初のパラメータ・タイプに代入できない場合に、ClassCastExceptionがスローされる可能性があります。 VirtualMachineErrorLinkageErrorおよびRuntimeExceptionの様々な例外タイプは、ほとんどすべての種類のJavaコードが原理内でスローされる可能性があることに注意してください。(例)のみを捕捉するfinally句は、IOException 3 codektj 4コードの外部キーをマスクします。

        パラメータ:
        target - 実行をtryブロックにラップするハンドル。
        cleanup - 最終ブロックで呼び出されるハンドル。
        戻り値:
        2つの引数で構成されるtry-finallyブロックを構成するメソッド・ハンドル。
        例外:
        NullPointerException - いずれかの引数がnullの場合
        IllegalArgumentException - cleanupが必須の先行引数を受け入れない場合、またはメソッド・ハンドル型が戻り型とそれに対応する後続パラメータで一致しない場合
        導入されたバージョン:
        9
        関連項目:
        catchException(MethodHandle, Class, MethodHandle)