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

クラスMethodHandles

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

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

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

    修飾子と型
    メソッド
    説明
    arrayConstructor(Class<?> arrayClass)
    anewarrayバイトコードの場合と同様に、必要な型の配列を構築するメソッド・ハンドルを生成します。
    arrayElementGetter(Class<?> arrayClass)
    aaloadバイトコードの場合と同様に、配列の要素に対する読み取りアクセスを提供するメソッド・ハンドルを生成します。
    arrayElementSetter(Class<?> arrayClass)
    astoreバイトコードの場合と同様に、配列の要素への書き込みアクセスを与えるメソッド・ハンドルを生成します。
    static VarHandle
    arrayClassの配列の要素にアクセスするVarHandleを生成します。
    arrayLength(Class<?> arrayClass)
    arraylengthバイトコードの場合と同様に、配列の長さを返すメソッド・ハンドルを生成します。
    static VarHandle
    byteArrayViewVarHandle(Class<?> viewArrayClass, ByteOrder byteOrder)
    int[]long[]など、異なるプリミティブ配列型であるかのように見えるbyte[]配列の要素へのアクセス権を付与するVarHandleを生成します。
    static VarHandle
    byteBufferViewVarHandle(Class<?> viewArrayClass, ByteOrder byteOrder)
    int[]またはlong[]など、byteの要素にアクセスするVarHandleを生成します。これは、ByteBufferの要素と異なるプリミティブ・コンポーネント型の要素の配列であるかのように見えます。
    catchException(MethodHandle target, Class<? extends Throwable> exType, MethodHandle handler)
    ターゲットのメソッド・ハンドルを例外ハンドラの内部で実行することによって、このターゲットを適応させるメソッド・ハンドルを作成します。
    static <T> T
    classData(MethodHandles.Lookup caller, String name, Class<T> type)
    指定されたcallerルックアップ・オブジェクトまたはnullのルックアップ・クラスに関連付けられた「クラス・データ」を返します。
    static <T> T
    classDataAt(MethodHandles.Lookup caller, String name, Class<T> type, int index)
    指定されたcallerルックアップ・オブジェクトのルックアップ・クラスに関連付けられているクラス・データがListの場合、「クラス・データ」の指定された索引にある要素を返します。
    collectArguments(MethodHandle target, int pos, MethodHandle filter)
    ターゲット・メソッド・ハンドルを、フィルタ(別のメソッド・ハンドル)でその引数のサブシーケンスを前処理することにより、適応させます。
    static VarHandle
    collectCoordinates(VarHandle target, int pos, MethodHandle filter)
    Preview.
    フィルタ(メソッド・ハンドル)を使用して座標値のサブ・シーケンスを前処理することで、ターゲット変数ハンドルを調整します。
    constant(Class<?> type, Object value)
    要求された戻り値の型を持ち、呼び出されるたびに指定された定数値を返すメソッド・ハンドルを生成します。
    指定された数の反復を実行するループを構築します。
    数値の範囲にわたってカウントするループを構築します。
    初期化子、本文および述語からdo-whileループを構築します。
    dropArguments(MethodHandle target, int pos, Class<?>... valueTypes)
    いくつかのダミー引数を破棄してから指定された別のtargetメソッド・ハンドルを呼び出すメソッド・ハンドルを生成します。
    dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes)
    いくつかのダミー引数を破棄してから指定された別のtargetメソッド・ハンドルを呼び出すメソッド・ハンドルを生成します。
    dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos)
    指定されたパラメータ・タイプ・リストと一致するようにターゲット・メソッド・ハンドルを適応させます。
    static VarHandle
    dropCoordinates(VarHandle target, int pos, Class<?>... valueTypes)
    Preview.
    ターゲットのvarハンドルに委譲する前にダミー座標を破棄するvarハンドルを返します。
    ターゲット・ハンドル(もしあれば)の戻り値を削除します。
    リクエストされた型のメソッド・ハンドルを生成します。引数は無視され、何も実行されず、戻り値の型に応じて適切なデフォルトが返されます。
    特殊なインボーカ・メソッド・ハンドルを生成します(これを使用すれば、指定された型の任意のメソッド・ハンドルを、invokeExactを使用する場合と同様に呼び出すことができる)。
    指定されたメソッド・ハンドルの型を新しい型に適応させるために、引数と戻り値の型の変換をペア単位で行うメソッド・ハンドルを生成します。
    filterArguments(MethodHandle target, int pos, MethodHandle... filters)
    ターゲット・メソッド・ハンドルを適応させるため、その1つ以上の引数をそれぞれ固有の単項フィルタ関数を使って前処理したあと、前処理を行った各引数を対応するフィルタ関数の結果で置き換えてターゲットを呼び出します。
    static VarHandle
    filterCoordinates(VarHandle target, int pos, MethodHandle... filters)
    Preview.
    単項フィルタ関数を使用して着信座標値を前処理することで、ターゲット変数ハンドルを適応させます。
    ターゲット・メソッド・ハンドルを適応させるため、その戻り値(存在する場合)をフィルタ(別のメソッド・ハンドル)で後処理します。
    static VarHandle
    filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget)
    Preview.
    フィルタ関数のペアを使用して受信値と送信値を事前処理することで、ターゲット変数ハンドルを適応させます。
    foldArguments(MethodHandle target, int pos, MethodHandle combiner)
    ターゲット・メソッド・ハンドルは、指定された位置から始めて、その引数の一部を前処理し、前処理の結果でターゲットをコールして、折り畳まれた引数の直前に元の引数のシーケンスに挿入することによって適応されます。
    ターゲット・メソッド・ハンドルを適応させるため、その引数のいくつかを前処理したあと、前処理の結果を元の一連の引数内に挿入してターゲットを呼び出します。
    テスト(boolean値のメソッド・ハンドル)で保護することでターゲット・メソッド・ハンドルを適応させるメソッド・ハンドルを作成します。
    identity(Class<?> type)
    呼出し時に唯一の引数の値を返すメソッド・ハンドルを生成します。
    insertArguments(MethodHandle target, int pos, Object... values)
    ターゲット・メソッド・ハンドルの呼出しの前に、1つ以上のバインド引数をメソッド・ハンドルに提供します。
    static VarHandle
    insertCoordinates(VarHandle target, int pos, Object... values)
    Preview.
    Varハンドル呼出しの前に、1つ以上の「バインド座標」を持つターゲットvarハンドルを提供します。
    特殊なインボーカ・メソッド・ハンドルを生成します(これを使用すれば、指定された型と互換性のある任意のメソッド・ハンドルを、invokeを使用する場合と同様に呼び出すことができる)。
    Iterator<T>によって生成された値の範囲にあるループを構築します。
    呼出し元のすべてのサポートされるバイトコード動作をエミュレートするためのフル機能を持つルックアップ・オブジェクトを返します。
    loop(MethodHandle[]... clauses)
    反復ごとに更新およびチェックされる複数のループ変数を持つループを表すメソッド・ハンドルを構築します。
    static VarHandle
    Preview.
    提供された値のレイアウトを使用して、特定のバイト・オフセットで「メモリー・セグメント」PREVIEWを間接参照するために使用できるvarハンドル・オブジェクトを作成します。
    permuteArguments(MethodHandle target, MethodType newType, int... reorder)
    引数の順序を変更することによって、指定されたメソッド・ハンドルの呼出し順序を新しい型に適応させるメソッド・ハンドルを生成します。
    static VarHandle
    permuteCoordinates(VarHandle target, List<Class<?>> newCoordinates, int... reorder)
    Preview.
    新しい座標が指定された座標と一致するように再配列することで、ターゲットのvarハンドルの座標値を適応させるvarハンドルを提供します。
    privateLookupIn(Class<?> targetClass, MethodHandles.Lookup caller)
    「プライベート・アクセス」を含む、サポートされているすべてのバイトコード動作をエミュレートするために、ターゲット・クラスのlookupオブジェクトを返します。
    最小の信頼レベルを持つルックアップ・オブジェクトを返します。
    static <T extends Member>
    T
    reflectAs(Class<T> expected, MethodHandle target)
    直接メソッド・ハンドルの未チェックの解読を実行します。
    spreadInvoker(MethodType type, int leadingArgCount)
    指定されたtypeの任意のメソッド・ハンドルを呼び出すメソッド・ハンドルを生成しますが、その際、指定された数の末尾の引数が単一の末尾のObject[]配列で置き換えられます。
    tableSwitch(MethodHandle fallback, MethodHandle... targets)
    表スイッチ・メソッド・ハンドルを作成します。これは、セレクタと呼ばれる特定のターゲット索引に基づいて、ターゲット・メソッド・ハンドルのセットを切り替えるために使用できます。
    throwException(Class<?> returnType, Class<? extends Throwable> exType)
    指定されたexTypeの例外をスローするメソッド・ハンドルを生成します。
    targetメソッド・ハンドルをtry-finallyブロックにラップして適応させるメソッド・ハンドルを作成します。
    特別な「呼び出しメソッドhandle」を生成します。このメソッドを使用して、関連付けられたアクセス・モード・タイプが指定のタイプと互換性がある任意のVarHandleでシグネチャ-多相アクセス・モード・メソッドを呼び出すことができます。
    特別な「呼び出しメソッドhandle」を生成します。このメソッドを使用して、関連付けられたアクセス・モード・タイプが指定のタイプと互換性がある任意のVarHandleでシグネチャ-多相アクセス・モード・メソッドを呼び出すことができます。
    初期化子、本文および述語からwhileループを構築します。
    zero(Class<?> type)
    リクエストされた戻り型の定数メソッド・ハンドルを生成します。このハンドルは、呼び出されるたびにその型のデフォルト値を返します。

    クラスjava.lang.Objectで宣言されたメソッド

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • メソッドの詳細

    • lookup

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

      このメソッドは呼出し元依存です。つまり、呼出し元ごとに異なる値を返す可能性があります。 スタック(例、JNIアタッチ・スレッドから直接コールされる場合)にコール元フレームがないコンテキストからMethodHandles.lookupがコールされると、IllegalCallerExceptionがスローされます。 このようなコンテキストでlookup objectを取得するには、コール元として暗黙的に識別される補助クラスを使用するか、かわりにpublicLookup()を使用して権限の低いルックアップを取得します。

      戻り値:
      originalおよび「完全な権限アクセス」での、このメソッドの呼出し側のルックアップ・オブジェクト。
      例外:
      IllegalCallerException - スタック上に呼び出し元フレームがない場合。
    • publicLookup

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

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

      APIのノート:
      Objectの使用は従来型であり、ルックアップ・モードは制限されているため、Object、そのパッケージまたはそのモジュールの内部に特別なアクセスは提供されません。 UNCONDITIONALモードでは、この公開された参照オブジェクトまたはその他の参照オブジェクトは、可読性を想定しています。 したがって、ルックアップ・クラスを使用してルックアップ・コンテキストが決定されません。

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

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

      public static MethodHandles.Lookup privateLookupIn(Class<?> targetClass, MethodHandles.Lookup caller) throws IllegalAccessException
      「プライベート・アクセス」を含む、サポートされているすべてのバイトコード動作をエミュレートするために、ターゲット・クラスのlookupオブジェクトを返します。 返された参照オブジェクトは、モジュールおよびパッケージ内のクラス、およびそれらのクラスのメンバーへのアクセスを提供できます。ただし、Javaアクセス制御の通常のルールの範囲外では、モジュラ「深い反射」のより許容性の高いルールに準拠します。

      モジュールM1では、Lookupオブジェクトとして指定されたコール元は、次のすべての条件がtrueの場合にのみ、モジュールM2およびターゲット・クラスのパッケージの深い反映が許可されます:

      • セキュリティ・マネージャが存在する場合は、checkPermissionメソッドが呼び出されてReflectPermission("suppressAccessChecks")がチェックされ、正常に戻す必要があります。
      • コール元参照オブジェクトには「完全な権限アクセス」が必要です。 具体的には、次のようになります。
        • コール元の参照オブジェクトには、MODULEの参照モードが必要です。 (これは、元のルックアップの作成者が特定のモジュールのメンバーであることを確認する方法がないためで、これ以降は、読みやすくするためのエクスポートと修飾エクスポートが無効になるチェックも行われるためです。)
        • コール元参照オブジェクトには、PRIVATEアクセス権が必要です。 (これは、MODULEのみを使用してモジュール内アクセスを共有するアプリケーションが意図せず、深いリフレクションを独自のモジュールと共有するためです。)
      • ターゲット・クラスは、プリミティブまたは配列クラスではなく、適切なクラスでなければなりません。 (したがって、M2は適切に定義されています。)
      • コール元モジュールM1がターゲット・モジュールM2と異なる場合、次の両方がtrueである必要があります:
        • M1 reads M2
        • M2 opens少なくともM1へのターゲット・クラスを含むパッケージ。

      前述のいずれかのチェックに違反している場合、このメソッドは例外を出力して失敗します。

      それ以外の場合、M1M2が同じモジュールであれば、このメソッドは「完全な権限アクセス」nullの以前のルックアップ・クラスを使用してtargetClass上のLookupを返します。

      それ以外の場合、M1M2は2つの異なるモジュールです。 このメソッドは、コール元のルックアップ・クラスをPRIVATEアクセス権を持つ新しい以前のルックアップ・クラスとして記録し、MODULEアクセス権を持たないLookuptargetClassで戻します。

      結果のLookupオブジェクトには、ORIGINALアクセス権がありません。

      APIのノート:
      このメソッドによって返されるLookupオブジェクトは、targetClassの実行時パッケージで「クラスの定義」に許可されます。 パッケージを別のモジュールに開く際には、targetClassのモジュール内の他のメンバーと同じ完全な権限アクセス権を持つように注意してください。
      パラメータ:
      targetClass - ターゲット・クラス
      caller - 呼び出し元参照オブジェクト
      戻り値:
      プライベート・アクセスを持つターゲット・クラスのルックアップ・オブジェクト
      例外:
      IllegalArgumentException - targetClassがプリミティブ・タイプ、voidまたは配列クラスの場合
      NullPointerException - targetClassまたはcallernullの場合
      SecurityException - セキュリティ・マネージャによって拒否された場合
      IllegalAccessException - 上に指定した他のアクセス・チェックのいずれかが失敗した場合
      導入されたバージョン:
      9
      関連項目:
    • classData

      public static <T> T classData(MethodHandles.Lookup caller, String name, Class<T> type) throws IllegalAccessException
      指定されたcallerルックアップ・オブジェクトまたはnullのルックアップ・クラスに関連付けられた「クラス・データ」を返します。

      クラス・データを含む非表示クラスは、Lookup::defineHiddenClassWithClassDataをコールすることで作成できます。 このメソッドにより、指定されたcallerルックアップ・オブジェクトのルックアップ・クラスの静的クラス・イニシャライザが実行されます(初期化されていない場合)。

      Lookup::defineHiddenClassによって作成された非表示クラスと非表示でないクラスには、クラス・データはありません。これらのクラスのルックアップ・オブジェクトでこのメソッドが呼び出されると、nullが返されます。

      クラス・データを取得するには、このルックアップの「ルックアップ・モード」「元のアクセス」が必要です。

      APIのノート:
      このメソッドは、動的に計算された定数のブートストラップ・メソッドとしてコールできます。 フレームワークでは、クラス・データ(ClassオブジェクトやMethodHandleオブジェクトなど)を使用して非表示クラスを作成できます。 クラス・データには、元の呼出し側によって作成されたルックアップ・オブジェクトからのみアクセスできますが、同じネスト内の他のメンバーからはアクセスできません。 フレームワークがクラス・データを介してセキュリティ上重要なオブジェクトを非表示クラスに渡す場合は、他のネストされたオブジェクトからアクセス可能なprivate staticフィールドにクラス・データを格納するのではなく、クラス・データの値を動的に計算された定数としてロードすることをお薦めします。
      型パラメータ:
      T - クラス・データ・オブジェクトのキャスト先の型
      パラメータ:
      caller - 操作を実行するクラスを説明する参照コンテキスト(通常はJVMによってスタック)
      name - ConstantDescs.DEFAULT_NAME ("_")である必要があります
      type - クラス・データの型
      戻り値:
      ルックアップ・クラスに存在する場合はクラス・データの値、そうでない場合はnull
      例外:
      IllegalArgumentException - 名前が"_"でない場合
      IllegalAccessException - ルックアップ・コンテキストにoriginalアクセス権がない場合
      ClassCastException - クラス・データを特定のtypeに変換できない場合
      NullPointerException - callerまたはtype引数がnullの場合
      Java Virtual Machine仕様を参照してください:
      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....)を作成し、このメソッドを使用して特定の索引で複数の要素をロードできます。 クラス・データには、元の呼出し側によって作成されたルックアップ・オブジェクトからのみアクセスできますが、同じネスト内の他のメンバーからはアクセスできません。 フレームワークがクラス・データを介してセキュリティ上重要なオブジェクトを非表示クラスに渡す場合は、他のネストされたオブジェクトからアクセス可能なprivate staticフィールドにクラス・データを格納するのではなく、クラス・データの値を動的に計算された定数としてロードすることをお薦めします。
      型パラメータ:
      T - 結果オブジェクトのキャスト先の型
      パラメータ:
      caller - 操作を実行するクラスを説明する参照コンテキスト(通常はJVMによってスタック)
      name - ConstantDescs.DEFAULT_NAME ("_")である必要があります
      type - クラス・データ内の指定されたインデックスにある要素の型
      index - クラス・データ内の要素の索引
      戻り値:
      クラス・データが存在する場合は、クラス・データ内の指定されたインデックスにある要素。それ以外の場合はnull
      例外:
      IllegalArgumentException - 名前が"_"でない場合
      IllegalAccessException - ルックアップ・コンテキストにoriginalアクセス権がない場合
      ClassCastException - クラス・データをListに変換できない場合、または指定された索引の要素を指定された型に変換できない場合
      IndexOutOfBoundsException - 索引が範囲外の場合
      NullPointerException - callerまたはtype引数が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 Virtual Machine仕様を参照してください:
      6.5 anewarray命令
      導入されたバージョン:
      9
      関連項目:
    • arrayLength

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

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

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

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

      返されたメソッド・ハンドルが呼び出されると、配列参照と配列インデックスがチェックされます。 配列リファレンスがnullの場合はNullPointerExceptionがスローされ、インデックスが負の場合または配列の長さ以上の場合はArrayIndexOutOfBoundsExceptionがスローされます。

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

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

      返されたメソッド・ハンドルが呼び出されると、配列参照と配列インデックスがチェックされます。 配列リファレンスがnullの場合はNullPointerExceptionがスローされ、インデックスが負の場合または配列の長さ以上の場合はArrayIndexOutOfBoundsExceptionがスローされます。

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

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

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

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

      コンポーネント型がfloatまたはdoubleの場合、数値およびアトミック更新アクセス・モードはビット単位の表現(それぞれ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の比較については異なります。 この操作が予期せず失敗する可能性があるため、これらの値との比較および設定または比較および交換操作の実行時には注意が必要です。 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のコンポーネント型の値との間でバイトを構成します。

      サポートされているコンポーネント・タイプ(変数の型)は、short, char, int, long, floatおよびdoubleです。

      インデックスが0より小さい場合、またはbyte[]配列の長さからTのサイズ(バイト単位)を引いた値より大きい場合、特定のインデックスでバイトにアクセスすると、ArrayIndexOutOfBoundsExceptionになります。

      配列および索引に関連付けられている基礎となるメモリー・アドレス(A)に関して、Tに対する索引のバイト・アクセスの整列または整列不良が考えられます。 アクセスが整列していない場合、getおよびsetアクセス・モード以外のアクセスは、IllegalStateExceptionになります。 そのような場合、アトミック・アクセスは、AのGCDとTのサイズ(バイト単位)を分割する2の最大の累乗に関してのみ保証されます。 アクセスが整列されている場合、次のアクセス・モードがサポートされ、アトミック・アクセスをサポートすることが保証されています:

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

      変数の型が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
      int[]またはlong[]など、byteの要素にアクセスするVarHandleを生成します。これは、ByteBufferの要素と異なるプリミティブ・コンポーネント型の要素の配列であるかのように見えます。 VarHandleの変数型はviewArrayClassのコンポーネント型で、座標型のリストは(ByteBuffer, int)です。ここで、int座標型はbyte[]配列への索引である引数に対応します。 戻されたVarHandleは、ByteBuffer内の索引のバイトにアクセスし、指定されたエンディアンに従って、viewArrayClassのコンポーネント型の値との間でバイトを構成します。

      サポートされているコンポーネント・タイプ(変数の型)は、short, char, int, long, floatおよびdoubleです。

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

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

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

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

      変数の型が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)
      特別な「呼び出しメソッドhandle」を生成します。このメソッドを使用して、関連付けられたアクセス・モード・タイプが指定のタイプと互換性がある任意のVarHandleでシグネチャ-多相アクセス・モード・メソッドを呼び出すことができます。 結果の呼出し側は、VarHandle型の追加の先行引数を受け入れることを除き、目的の型と完全に等しい型を持ちます。
      パラメータ:
      accessMode - VarHandleアクセス・モード
      type - 目的となるターゲットの型
      戻り値:
      アクセス・モード・タイプが指定されたタイプのVarHandleのアクセス・モード・メソッドの呼出しに適したメソッド・ハンドル。
      導入されたバージョン:
      9
    • varHandleInvoker

      public static MethodHandle varHandleInvoker(VarHandle.AccessMode accessMode, MethodType type)
      特別な「呼び出しメソッド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の場合と同じ変換が許可されるほか、それらの変換が失敗した場合には、いくつかの追加の変換も適用されます。 asTypeで行われる変換の前に、あるいはその代わりに、次のいずれかの変換が可能であれば適用されます(T0T1は型)。

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

      パラメータ:
      target - 引数の型を調整したあとに呼び出すメソッド・ハンドル
      newType - 新しいメソッド・ハンドルの期待される型
      戻り値:
      必要な引数変換をすべて実行したあとでターゲットに委譲し、必要なあらゆる戻り値変換の手配も行うメソッド・ハンドル
      例外:
      NullPointerException - どちらかの引数がnullの場合
      WrongMethodTypeException - 変換できない場合
      関連項目:
    • 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
      関連項目:
    • 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
      関連項目:
    • 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 - pos0より小さいか、N - Lより大きい場合、Nはターゲット・メソッド・ハンドルのアリティ、Lは値配列の長さです。
      ClassCastException - 引数が対応するバウンド・パラメータ・タイプと一致しない場合。
      関連項目:
    • 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 - 引数を除去したあとに呼び出すメソッド・ハンドル
      pos - 除去する最初の引数の位置(左端の場合は0)
      valueTypes - 除去する引数の型
      戻り値:
      指定された型の引数を除去してから元のメソッド・ハンドルを呼び出すメソッド・ハンドル
      例外:
      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 - 引数を除去したあとに呼び出すメソッド・ハンドル
      pos - 除去する最初の引数の位置(左端の場合は0)
      valueTypes - 除去する引数の型
      戻り値:
      指定された型の引数を除去してから元のメソッド・ハンドルを呼び出すメソッド・ハンドル
      例外:
      NullPointerException - ターゲットがnullの場合、またはvalueTypes配列またはそのいずれかの要素がnullの場合
      IllegalArgumentException - valueTypesのいずれかの要素がvoid.classの場合、またはposが負またはターゲットの引数カウントより大きい場合、または新しいメソッド・ハンドルの型のパラメータ数が多すぎる場合
    • dropArgumentsToMatch

      public static MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos)
      指定されたパラメータ・タイプ・リストと一致するようにターゲット・メソッド・ハンドルを適応させます。 必要に応じて、ダミーの引数を追加します。 一部の先行パラメータは、照合の開始前にスキップできます。 targetのパラメータ・タイプ・リストの残りのタイプは、開始位置posにあるnewTypesタイプ・リストのサブリストである必要があります。 結果のハンドルには、ターゲット・ハンドルのパラメータ・タイプ・リストがあり、一致しないパラメータ・タイプ(一致するサブリストの前後に)が、dropArguments(MethodHandle, int, Class[])のように、ターゲットの元のパラメータの対応する位置に挿入されます。

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

      より正式な用語では、次の2つのタイプ・リストを想定します:

      • ターゲット・ハンドルは、skipで示されるように、Sに多くの型を持つパラメータ型リストS..., M...を持っています。 M型は、指定された型リストnewTypesの一部と一致すると想定される型です。
      • newTypesリストには、posで示されるように、Pに多くの型が含まれるP..., M..., A...型が含まれています。 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リスト・サイズより大きい場合、またはnewTypesが位置postargetの非スキップ・パラメータ・タイプを含まない場合。
      導入されたバージョン:
      9
    • dropReturn

      public static MethodHandle dropReturn(MethodHandle target)
      ターゲット・ハンドル(もしあれば)の戻り値を削除します。 返されるメソッド・ハンドルは、voidの戻り型を持ちます。
      パラメータ:
      target - 適応するメソッド・ハンドル
      戻り値:
      場合によっては適合したメソッド・ハンドル
      例外:
      NullPointerException - targetがnullである場合
      導入されたバージョン:
      16
    • 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"));
      

      次に、結果のアダプタの疑似コードを示します。 コードで、Tは、targetおよび結果のアダプタの戻り型を表します。 V/vは、Vvoidでないかぎり、targetのシグネチャおよび引数にもそれぞれ存在するfilterの戻り型および値の表記です。 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からターゲットの引数カウントの間(含む)にない場合、または結果のメソッド・ハンドルの型のパラメータ数が多すぎる場合
      関連項目:
    • 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);
      }
      

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

      パラメータ:
      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"));
      

      次に、結果のアダプタの疑似コードを示します。 コードで、Tは、targetの結果タイプと結果のアダプタを表します。 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"));
      

      次に、結果のアダプタの疑似コードを示します。 コードで、Tは、targetの結果タイプと結果のアダプタを表します。 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の戻り型は、ターゲット・シグネチャの位置posの引数型と同じでなく、void以外です。(2)ターゲット・シグネチャ(combinerの戻り型と一致する1つをスキップ)の位置posN引数型は、combinerの引数型とは同一ではありません。
      導入されたバージョン:
      9
      関連項目:
    • guardWithTest

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

      次に、結果のアダプタの疑似コードを示します。 コードで、Tは、関連する3つのハンドルの均一な結果タイプ(A/atestで使用されるtargetパラメータおよび引数の型と値、およびB/b)を表します。これらの型と値は、testでは使用されない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が指定された例外の型を受け入れない場合、またはメソッド・ハンドルの型に含まれる戻り値の型と対応するパラメータが一致しない場合
      関連項目:
    • 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つ以上の"clauses"によって形成され、それぞれがローカルの「反復変数」またはループ終了(あるいはその両方)を指定します。 ループの各反復処理では、各句が順番に実行されます。 句はオプションで反復変数を更新できます。オプションで、テストおよび条件付きループの終了を実行することもできます。 メソッド・ハンドルに関してこのロジックを表現するために、各句では最大4つの独立したアクションを指定します:

      • init: ループが実行される前に、V型の反復変数vの初期化を行います。
      • ステップ: 句が実行されると、反復変数vの更新ステップが実行されます。
      • pred: 句が実行されると、ループ終了をテストする述語の実行。
      • 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*)の場合も同様です)の任意のプレフィクスを表現します。 この表記法では、初期化パラメータ・パラメータ・リストの一般的な形式は(A*)で、非initファンクション・パラメータ・リストの一般的な形式は(V*)または(V... A*)です。

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

      効果的に同一の配列: パラメータ・リストAは、ABが同じ場合、またはAが短く、Bの適切なプレフィクスと同じ場合、別のパラメータ・リストBに対して効果的に同一として定義されます。 順序付けられていないパラメータ・リスト・セットについて言えば、セットに最長のリストが含まれ、セットのすべてのメンバーがその最長のリストと事実上同じである場合は、セットが全体として"効果的に同一"であるとします。 たとえば、(V*)形式の型シーケンスのセットは実質的に同一であり、(V... A*)形式のシーケンスがさらに追加された場合は同じです。

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

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

      ステップ1A: 繰り返し変数の型(V...)を決定します。

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

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

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

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

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

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

      1. 少なくとも1つの非省略予測関数が必要です。
      2. 省略されないすべての予測関数には、boolean戻り型が必要です。

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

      1. 結果のループ・ハンドルのパラメータ・リストは、外部パラメータ・リスト(A...)になります。
      2. init関数のパラメータ・リストは、外部パラメータ・リストに調整されます。 (これらのパラメータ・リストは、すでにこのリストと実質的に同じです。)
      3. 省略されていない非初期化の(step、pred、fini)関数のパラメータ・リストは、内部パラメータ・リスト(V... A...)と実質的に同じである必要があります。

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

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

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

      1. この時点で、すべてのinit関数パラメータ・リストは、外部パラメータ・リスト(A...)と実質的に同じですが、一部のリストが短い場合があります。 短いパラメータ・リストを持つすべてのinit関数について、リストの末尾を埋め込みます。
      2. この時点で、すべての非init関数パラメータ・リストは、内部パラメータ・リスト(V... A...)と実質的に同じですが、一部のリストが短い場合があります。 短いパラメータ・リストを持つすべての非init関数について、リストの末尾を埋め込みます。
      3. 引数リストは「未使用の末尾の引数を削除」によって埋められます。

      最終的な観察。

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

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

      • Nn = 1..NCn = {null, Sn, Pn}を指定すると仮定します。
      • 述語ハンドル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...)がステップ関数から導出されています。これは、ほとんどのループ計算がステップで発生する場合に自然です。 一部のループでは、計算の負荷が予測関数で最も大きくなる可能性があるため、予測関数はループ・パラメータ値を受け入れる必要がある場合があります。 複雑な終了ロジックを持つループの場合、fini関数はループ・パラメータを受け入れる必要があり、同様に、複雑なエントリ・ロジックを持つループでは、init関数に余分なパラメータが必要になることがあります。 このような理由から、これらのパラメータを決定するルールは、すべての句の部分で可能なかぎり対称です。 一般に、ループ・パラメータはループ全体で共通の不変値として機能し、反復変数は共通のバリアント値、または(ステップ機能がない場合)は内部ループ不変時間を表します。

      ループの実行。

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

      使用上のヒント。

      • 各ステップ・ファンクションは、ループ変数allの現在の値を受け取りますが、ステップ・ファンクションが独自の変数の現在の値のみを監視する必要がある場合があります。 その場合、ステップ関数で明示的に「前のすべてのループ変数を削除」が必要になることがあります。 これには、dropArguments(step, 0, V0.class, ...)のような式で型を記述する必要があります。
      • ループ変数は、変更する必要はありません。ループ不変変数にすることができます。 句は、ステップ、プレッドまたはfini関数を含まない適切なinit関数によってループ不変式を作成できます。 これは、隣接するループ変数のステップまたは前関数への着信ループ引数を"wire"する場合に役立ちます。
      • 一部の句関数がインスタンス上の仮想メソッドである場合、new MethodHandle[]{identity(ObjType.class)}などの初期句を使用して、インスタンス自体を初期不変ループ"variable"に簡単に配置できます。 その場合、インスタンス参照は最初の反復変数値になり、句部分として仮想メソッドを簡単に使用できます。これは、すべてのインスタンス参照がその値と一致する先行インスタンス参照を取るためです。

      結果のループ・ハンドルの疑似コードを次に示します。 前述のように、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-tuples)の配列。
      戻り値:
      引数によって定義されたループ動作を具体化するメソッド・ハンドル。
      例外:
      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という名前に割り当て、voidVがパラメータ・リストから静かに削除され、(A...)Vが残ることを理解して(V A...)Vを記述します。)
      • 本文のパラメータ・リスト(V A...)は、「内部パラメータ・リスト」と呼ばれます。 他のループ部分のパラメータ・リストを制約します。
      • 反復変数タイプVが内部パラメータ・リストから削除されると、結果の短いリスト(A...)「外部パラメータ・リスト」と呼ばれます。
      • 本文の戻り型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 - predまたはbodynullの場合。
      導入されたバージョン:
      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という名前に割り当て、voidVがパラメータ・リストから静かに削除され、(A...)Vが残ることを理解して(V A...)Vを記述します。)
      • 本文のパラメータ・リスト(V A...)は、「内部パラメータ・リスト」と呼ばれます。 他のループ部分のパラメータ・リストを制約します。
      • 反復変数タイプVが内部パラメータ・リストから削除されると、結果の短いリスト(A...)「外部パラメータ・リスト」と呼ばれます。
      • 本文の戻り型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 - predまたはbodynullの場合。
      導入されたバージョン:
      9
      関連項目:
    • 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変数がない場合はvoid)の最後のV値になります。

      引き数ハンドルには次の規則があります:

      • iterationsハンドルは、nullではなく、int型を戻す必要があります。ここでは、パラメータ型リストでIと呼びます。
      • 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を戻す必要があります。
      • initが非nullの場合、戻り型は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にはできません。 標準ケース(詳細は上記を参照)でループ・パラメータと結果型を制御します。 独自の戻り型(非空白の場合)とintパラメータ(カウンタのために)を受け入れる必要があり、任意の数の追加型を受け入れることができます。 その他の制約については、上記を参照してください。
      戻り値:
      ループを表すメソッド・ハンドル。
      例外:
      NullPointerException - iterationsまたはbodyハンドルのいずれかがnullの場合。
      IllegalArgumentException - いずれかの引数が上記の規則に違反している場合。
      導入されたバージョン:
      9
      関連項目:
    • countedLoop

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

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

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

      各反復では、反復変数がbodyハンドルの呼出しに渡されます。 本文(型Vの)から返されたvoid以外の値は、先頭の反復変数を更新します。 ループ・ハンドル実行の結果は、その変数(V変数がない場合はvoid)の最後のV値になります。

      引き数ハンドルには次の規則があります:

      • 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を戻す必要があります。
      • initが非nullの場合、戻り型は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 - ループ・カウンタ(ループはend-1に実行されます)の終了値を返す非nullハンドル。 結果の型はintでなければなりません。 その他の制約については、上記を参照してください。
      init - オプションのイニシャライザ。ループ変数の初期値を指定します。 nullの場合があり、デフォルトの初期値を示します。 その他の制約については、上記を参照してください。
      body - ループの本文。nullにはできません。 標準ケース(詳細は上記を参照)でループ・パラメータと結果型を制御します。 独自の戻り型(非空白の場合)とintパラメータ(カウンタのために)を受け入れる必要があり、任意の数の追加型を受け入れることができます。 その他の制約については、上記を参照してください。
      戻り値:
      ループを表すメソッド・ハンドル。
      例外:
      NullPointerException - startend、またはbodyハンドルのいずれかがnullである場合。
      IllegalArgumentException - いずれかの引数が上記の規則に違反している場合。
      導入されたバージョン:
      9
      関連項目:
    • 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変数がない場合はvoid)の最後のV値になります。

      引き数ハンドルには次の規則があります:

      • 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を戻す必要があります。
      • initが非nullの場合、戻り型はVでなければなりません。 そのパラメータ・リスト(いくつかの「フォーム(A*)の)は、外部パラメータ・リスト(A...)に対して「効果的に同一」でなければなりません。
      • initnullの場合、ループ変数は「デフォルト値」に初期化されます。
      • iteratorハンドルがnull以外の場合、戻り型はjava.util.Iteratorまたはサブタイプである必要があります。 ループが実行されたときに生成されるイテレータは、T型に変換可能な値を生成すると見なされます。
      • null (いくつかの形式の(A*)の)であるiteratorのパラメータ・リストは、外部パラメータ・リスト(A...)と実質的に同一でなければなりません。
      • iteratornullの場合、デフォルトではIterable.iterator()のように動作するメソッド・ハンドルになります。 その場合、内部パラメータ・リスト(V T A...)には少なくとも1つのAタイプが必要です。また、デフォルトのイテレータ・ハンドル・パラメータは、asType変換メソッドの場合と同様に、先頭のAタイプを受け入れるように調整されます。 先頭のA型は、Iterableまたはそのサブタイプである必要があります。 この変換ステップは、ループ構築時に実行され、WrongMethodTypeExceptionをスローしないでください。

      T型は、プリミティブまたは参照のいずれかです。 Iterator<T>型はメソッド・ハンドル表現でRAW型Iteratorに消去されるため、iteratedLoopコンビネータは、bodyObjectへの先頭引数型を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ハンドルが最初に例外をスローしないかぎり、例外は再スローされます。 cleanupハンドルの実行から返される値は、try-finallyハンドルの実行結果になります。

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

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

      • Throwableは、targetは、targetハンドル(もしあれば)によってスローされた例外を運びます。そして
      • targetおよびcleanupの両方の戻り型と同じ型のパラメータ。このパラメータは、targetハンドルの実行の結果を保持します。 targetvoidを返した場合、このパラメータは存在しません。

      結果のアダプタの疑似コードは次のようになります。 コード内の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を宣言することをお薦めします。 これにより、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
      関連項目:
    • tableSwitch

      public static MethodHandle tableSwitch(MethodHandle fallback, MethodHandle... targets)
      表スイッチ・メソッド・ハンドルを作成します。これは、セレクタと呼ばれる特定のターゲット索引に基づいて、ターゲット・メソッド・ハンドルのセットを切り替えるために使用できます。

      セレクタ値n (n[0, N)の範囲内にあり、Nはターゲット・メソッド・ハンドルの数)の場合、表スイッチ・メソッド・ハンドルは、ターゲット・メソッド・ハンドルのリストからn番目のターゲット・メソッド・ハンドルを起動します。

      [0, N)の範囲内にないセレクタ値の場合、表スイッチ・メソッド・ハンドルは指定されたフォールバック・メソッド・ハンドルを起動します。

      このメソッドに渡すメソッド・ハンドルはすべて同じタイプである必要があり、先行するパラメータがintタイプであるという追加の要件があります。 先頭パラメータはセレクタを表します。

      型に存在する後続のパラメータも、返されるテーブル・スイッチ・メソッド・ハンドルに表示されます。 これらのパラメータに割り当てられた引数は、セレクタ値と共に、起動時に選択したメソッド・ハンドルに転送されます。

      APIのノート:
      例: 各ケースでは、指定されたselector値をドロップし、(String.concat(String)を使用して)を特定の定数ラベル文字列に連結した追加の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 - fallbackの場合、targets配列、またはtargets配列の要素のいずれかがnullです。
      IllegalArgumentException - targets配列が空の場合、フォールバック・ハンドルまたはいずれかのターゲット・ハンドルの先頭パラメータがintでない場合、またはフォールバック・ハンドルのタイプとすべてのターゲット・ハンドルが同じでない場合。
    • memorySegmentViewVarHandle

      public static VarHandle memorySegmentViewVarHandle(ValueLayoutPREVIEW layout)
      memorySegmentViewVarHandleは、JavaプラットフォームのプレビューAPIです。
      プレビュー機能が有効な場合のみ、プログラムでmemorySegmentViewVarHandleを使用できます。
      プレビュー機能は、今後のリリースで削除するか、Javaプラットフォームの永続機能にアップグレードすることができます。
      提供された値のレイアウトを使用して、特定のバイト・オフセットで「メモリー・セグメント」PREVIEWを間接参照するために使用できるvarハンドル・オブジェクトを作成します。

      指定されたレイアウトでは、返されたvarハンドルに関連付けられた「キャリア・タイプ」PREVIEW「バイト・サイズ」PREVIEW「バイト整列」PREVIEWおよび「バイト・オーダー」PREVIEWを指定します。

      返されるvarハンドルに関連付けられた座標タイプのリストは、(MemorySegment, long)です。long座標タイプは、指定されたメモリー・セグメント座標へのバイト・オフセットに対応します。 したがって、返されるvarハンドルは、指定されたメモリー・セグメント内のオフセットにあるバイトにアクセスし、varハンドル・タイプの値との間のバイトを作成します。 さらに、アクセス操作では、指定されたレイアウトで表されるエンディアンおよび整列制約が適用されます。

      例として、次のように構築されたGroupLayoutPREVIEWインスタンスによって表されるメモリー・レイアウトについて考えてみます:

          GroupLayout seq = java.lang.foreign.MemoryLayout.structLayout(
                  MemoryLayout.paddingLayout(4),
                  ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value")
          );
      
      valueという名前のメンバー・レイアウトにアクセスするには、次のようにメモリー・セグメント・ビューのvarハンドルを構築できます:
          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で発生する場合、「完全に整列」であるとします。 アクセスが完全に整列されている場合、次のアクセス・モードがサポートされ、原子性アクセスをサポートする保証があります:
      • すべてのTの読取り書込みアクセス・モード(longの場合はアクセス・モードgetおよびset、32ビット・プラットフォームの場合はdoubleを除く)。
      • int, long, float, doubleまたはMemorySegmentPREVIEWのアトミック更新アクセス・モード。 (JDKの将来のメジャー・プラットフォーム・リリースでは、現在サポートされていない特定のアクセス・モードの追加タイプがサポートされる場合があります。)
      • intlongおよびMemorySegmentPREVIEWの数値アトミック更新アクセス・モード。 (JDKの将来のメジャー・プラットフォーム・リリースでは、現在サポートされていない特定のアクセス・モードに対して追加の数値型をサポートする場合があります。)
      • intlongおよびMemorySegmentPREVIEWのビット単位のアトミック更新アクセス・モード。 (JDKの将来のメジャー・プラットフォーム・リリースでは、現在サポートされていない特定のアクセス・モードに対して追加の数値型をサポートする場合があります。)
      TfloatdoubleまたはMemorySegmentPREVIEWの場合、アトミック更新アクセス・モードはビット単位表現(それぞれFloat.floatToRawIntBits(float)Double.doubleToRawLongBits(double)およびMemorySegment.address()PREVIEWを参照してください)を使用して値を比較します。

      あるいは、メモリー・アクセス操作が、位置情報制約Bとのみ互換性のあるメモリー・アドレスAで発生する場合、「部分的に整列」です。その場合、getおよびsetアクセス・モード以外でアクセスするとIllegalStateExceptionになります。 アクセスが部分的に整列されている場合、アトミック・アクセスは、AおよびSのGCDを分割する2の最大電力に関してのみ保証されます。

      それ以外の場合は、メモリー・アクセス操作が「右揃え」であるとします。この場合、使用中のアクセス・モードに関係なく、IllegalStateExceptionがスローされます。

      最後に、TMemorySegmentの場合、書き込まれる値が「ネイティブ」PREVIEWメモリー・セグメントでないかぎり、すべての書込みアクセス・モードはIllegalArgumentExceptionをスローします。

      パラメータ:
      layout - メモリー・アクセス・ハンドルを取得する値レイアウト。
      戻り値:
      新しいメモリー・セグメント・ビュー可変ハンドル。
      例外:
      NullPointerException - layoutnullの場合。
      導入されたバージョン:
      19
      関連項目:
    • filterValue

      public static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget)
      filterValueは、JavaプラットフォームのプレビューAPIです。
      プレビュー機能が有効な場合のみ、プログラムでfilterValueを使用できます。
      プレビュー機能は、今後のリリースで削除するか、Javaプラットフォームの永続機能にアップグレードすることができます。
      フィルタ関数のペアを使用して受信値と送信値を事前処理することで、ターゲット変数ハンドルを適応させます。

      たとえば、結果のvarハンドルでVarHandle.set(Object...)をコールすると、最初のフィルタを使用して受信値(Tタイプ。Tは最初のフィルタ関数のlastパラメータ・タイプです。)が処理され、ターゲットのvarハンドルに渡されます。 逆に、結果のvarハンドルで、たとえば、VarHandle.get(Object...)などをコールすると、ターゲットのvarハンドル(Tタイプ。Tは、2番目のフィルタ関数のlastパラメータ・タイプです。)から取得された戻り値は、2番目のフィルタを使用して処理され、コール元に戻されます。 VarHandle.AccessMode.COMPARE_AND_EXCHANGEなどのより高度なアクセス・モード・タイプでは、両方のフィルタが同時に適用される場合があります。

      ボクシング・フィルタおよびアンボックス・フィルタを整形式にするには、それぞれ(A... , S) -> Tおよび(A... , T) -> Sの形式にする必要があります(Tはターゲット変数ハンドルのタイプです)。 この場合、結果のvarハンドルはS型になり、追加の座標A... (ターゲット変数ハンドルの座標に追加されます。)を特徴とします。

      ボクシング・フィルタおよびアンボックス化フィルタが呼び出されたときにチェック例外をスローすると、結果のvarハンドルはIllegalStateExceptionをスローします。

      結果のvarハンドルには、ターゲットのvarハンドルの機能と同じアクセス・モードである(VarHandle.AccessModeを参照してください)およびアトミック・アクセスが保証されます。

      パラメータ:
      target - ターゲット変数ハンドル
      filterToTarget - 一部のタイプのStargetのタイプに変換するフィルタ
      filterFromTarget - targetのタイプをSのタイプに変換するフィルタ
      戻り値:
      指定されたボクシング/アン・ボクシング変換を実行して、新しい型を受け入れるアダプタ変数ハンドル。
      例外:
      IllegalArgumentException - filterFromTargetおよびfilterToTargetの形式が適切でない場合、つまり、それぞれ(A... , S) -> Tおよび(A... , T) -> S以外の型があり、Tはターゲット変数ハンドルのタイプであるか、filterFromTargetまたはfilterToTargetのいずれかがチェックされた例外をスローすると判断された場合。
      NullPointerException - 引数のいずれかがnullの場合。
      導入されたバージョン:
      19
    • filterCoordinates

      public static VarHandle filterCoordinates(VarHandle target, int pos, MethodHandle... filters)
      filterCoordinatesは、JavaプラットフォームのプレビューAPIです。
      プレビュー機能が有効な場合のみ、プログラムでfilterCoordinatesを使用できます。
      プレビュー機能は、今後のリリースで削除するか、Javaプラットフォームの永続機能にアップグレードすることができます。
      単項フィルタ関数を使用して着信座標値を前処理することで、ターゲット変数ハンドルを適応させます。

      たとえば、結果のvarハンドルで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以外のタイプがあり、posが0の間でない場合は、T1, T2 ... Tnはターゲット変数ハンドルの位置posから始まる座標タイプです。また、ターゲット変数ハンドルの座標アリティ(包含)や、posから始まる実際の座標タイプ数よりも多くのフィルタが指定されている場合、またはいずれかのフィルタがチェックされた例外をスローすることを決定した場合。
      NullPointerException - 引数のいずれかがnullであるか、filtersnullが含まれている場合。
      導入されたバージョン:
      19
    • insertCoordinates

      public static VarHandle insertCoordinates(VarHandle target, int pos, Object... values)
      insertCoordinatesは、JavaプラットフォームのプレビューAPIです。
      プレビュー機能が有効な場合のみ、プログラムでinsertCoordinatesを使用できます。
      プレビュー機能は、今後のリリースで削除するか、Javaプラットフォームの永続機能にアップグレードすることができます。
      Varハンドル呼出しの前に、1つ以上の「バインド座標」を持つターゲットvarハンドルを提供します。 その結果、結果のvarハンドルは、ターゲットのvarハンドルよりも座標型が少なくなります。

      たとえば、結果のvarハンドルでVarHandle.get(Object...)をコールすると、着信座標値がバインドされた座標値と結合され、ターゲットのvarハンドルに渡されます。

      境界座標を整形するには、その型はT1, T2 ... Tn である必要があります。T1, T2 ... Tnは、ターゲット変数ハンドルの位置posから始まる座標タイプです。

      結果のvarハンドルには、ターゲットのvarハンドルの機能と同じアクセス・モードである(VarHandle.AccessModeを参照してください)およびアトミック・アクセスが保証されます。

      パラメータ:
      target - バインドされた座標が挿入された後に呼び出すvarハンドル
      pos - 挿入する最初の座標の位置
      values - 挿入する一連のバウンド座標
      戻り値:
      ターゲットvarハンドルをコールする前に追加の座標を挿入するアダプタvarハンドル
      例外:
      IllegalArgumentException - posが0からターゲットのvarハンドル座標引数(両端を含む)の間にない場合、またはposから使用可能な座標タイプの実際の数よりも多くの値が指定されている場合。
      ClassCastException - valuesのバインドされた座標が整形式でない場合、つまり、T1, T2 ... Tn 以外の型を持つ場合(T1, T2 ... Tnはターゲット変数ハンドルのposの位置から始まる座標型です)。
      NullPointerException - 引数のいずれかがnullであるか、valuesnullが含まれている場合。
      導入されたバージョン:
      19
    • permuteCoordinates

      public static VarHandle permuteCoordinates(VarHandle target, List<Class<?>> newCoordinates, int... reorder)
      permuteCoordinatesは、JavaプラットフォームのプレビューAPIです。
      プレビュー機能が有効な場合のみ、プログラムでpermuteCoordinatesを使用できます。
      プレビュー機能は、今後のリリースで削除するか、Javaプラットフォームの永続機能にアップグレードすることができます。
      新しい座標が指定された座標と一致するように再配列することで、ターゲットのvarハンドルの座標値を適応させるvarハンドルを提供します。

      指定された配列によって並べ替えが制御されます。 着信座標数(値newCoordinates.size())を#Iにコールし、発信座標数(ターゲット変数ハンドルに関連付けられた座標の数)を#Oにコールします。 このとき、並べ替え配列の長さは#O、各要素は#Iより小さい負でない数でなければいけません。 #O未満のすべてのNについて、N番目の送信座標は、Ireorder[N]であるI番目の受信座標から取得されます。

      座標値の変換は適用されません。 newCoordinatesによって決定される各受信座標の型は、ターゲット変数ハンドル内の対応する送信座標の型と同じである必要があります。

      並べ替え配列では、実際の入れ替えを指定する必要はありません。 入力座標は、そのインデックスが配列内に複数回出現する場合は複製され、インデックスが配列内に存在しない場合は入力座標が削除されます。

      結果のvarハンドルには、ターゲットのvarハンドルの機能と同じアクセス・モードである(VarHandle.AccessModeを参照してください)およびアトミック・アクセスが保証されます。

      パラメータ:
      target - 座標が並べ替えられた後に呼び出すvarハンドル
      newCoordinates - 新しい座標型
      reorder - 並べ替えを制御するインデックス配列
      戻り値:
      ターゲットのvarハンドルを呼び出す前に、着信座標値を再配置するアダプタのvarハンドル
      例外:
      IllegalArgumentException - 索引配列の長さがターゲットのvarハンドルの座標数と等しくない場合、索引配列要素がnewCoordinatesの座標に対して有効な索引でない場合、またはターゲットのvarハンドルとnewCoordinatesの対応する座標タイプが同じでない場合。
      NullPointerException - 引数のいずれかがnullであるか、newCoordinatesnullが含まれている場合。
      導入されたバージョン:
      19
    • collectCoordinates

      public static VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter)
      collectCoordinatesは、JavaプラットフォームのプレビューAPIです。
      プレビュー機能が有効な場合のみ、プログラムでcollectCoordinatesを使用できます。
      プレビュー機能は、今後のリリースで削除するか、Javaプラットフォームの永続機能にアップグレードすることができます。
      フィルタ(メソッド・ハンドル)を使用して座標値のサブ・シーケンスを前処理することで、ターゲット変数ハンドルを調整します。 前処理された座標はフィルタ関数の結果(もしあれば)に置き換えられ、変更された(通常は短縮)座標リストでターゲット変数ハンドルが呼び出されます。

      Rがフィルタ(voidにはできません)の戻り型である場合、ターゲット変数ハンドルは、posの位置の座標として、フィルタに渡されない座標の前または後ろ(あるいはその両方)にR型の値を受け入れる必要があります。 座標の順序は変更されず、フィルタから返される結果は、最初にアダプタに渡された座標のサブ・シーケンス全体を(順番)に置き換えます。

      フィルタの引数の型(もしあれば)は、調整後のvarハンドルの位置posにあるターゲットvarハンドルのゼロまたは1つの座標型を置き換えます。 フィルタの戻り型は、posの位置にあるターゲット変数ハンドルの座標型と同じである必要があり、そのターゲット変数ハンドル座標はフィルタの戻り値によって提供されます。

      いずれかのフィルタが呼び出されたときにチェック例外をスローした場合、結果のvarハンドルはIllegalStateExceptionをスローします。

      結果のvarハンドルには、ターゲットのvarハンドルの機能と同じアクセス・モードである(VarHandle.AccessModeを参照してください)およびアトミック・アクセスが保証されます。

      パラメータ:
      target - 座標がフィルタ処理された後に呼び出すvarハンドル
      pos - フィルタ処理される座標の位置
      filter - フィルタ・メソッド・ハンドル
      戻り値:
      ターゲットのvarハンドルを呼び出す前に、着信座標値をフィルタ処理するアダプタのvarハンドル
      例外:
      IllegalArgumentException - filterの戻り型が無効である場合、またはターゲット変数ハンドルの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はターゲットのvarハンドル座標型の引数です。 posがゼロの場合、ダミー座標はターゲットの実引数の前に配置され、posNの場合は後ろに配置されます。

      結果のvarハンドルには、ターゲットのvarハンドルの機能と同じアクセス・モードである(VarHandle.AccessModeを参照してください)およびアトミック・アクセスが保証されます。

      パラメータ:
      target - ダミー座標がドロップされた後に呼び出すvarハンドル
      pos - (左端のゼロ)を削除する最初の座標の位置
      valueTypes - ドロップする座標の型
      戻り値:
      ターゲットvarハンドルを呼び出す前にダミー座標をドロップするアダプタvarハンドル
      例外:
      IllegalArgumentException - posが0からターゲットのvarハンドル座標引数(両端を含む)の間にない場合。
      NullPointerException - 引数のいずれかがnullであるか、valueTypesnullが含まれている場合。
      導入されたバージョン:
      19