public class MethodHandles extends Object
- メソッドやフィールドのメソッド・ハンドルの作成に役立つルックアップ・メソッド。
- 既存のメソッド・ハンドルを組み合わせたり変換したりして新しいハンドルを作成するコンビネータ・メソッド。
- その他の一般的なJVM操作や制御フロー・パターンをエミュレートするメソッド・ハンドルを作成する、その他のファクトリ・メソッド。
IllegalArgumentException
がスローされます。- 導入されたバージョン:
- 1.7
-
ネストされたクラスのサマリー
ネストされたクラス 修飾子と型 クラス 説明 static class
MethodHandles.Lookup
ルックアップ・オブジェクトは、メソッド・ハンドルの作成にアクセス・チェックが必要な場合のメソッド・ハンドル作成用ファクトリです。 -
メソッドのサマリー
修飾子と型 メソッド 説明 static MethodHandle
arrayConstructor(Class<?> arrayClass)
anewarray
バイトコードの場合と同様に、必要な型の配列を構築するメソッド・ハンドルを生成します。static MethodHandle
arrayElementGetter(Class<?> arrayClass)
aaload
バイトコードの場合と同様に、配列の要素に対する読み取りアクセスを提供するメソッド・ハンドルを生成します。static MethodHandle
arrayElementSetter(Class<?> arrayClass)
astore
バイトコードの場合と同様に、配列の要素への書き込みアクセスを与えるメソッド・ハンドルを生成します。static VarHandle
arrayElementVarHandle(Class<?> arrayClass)
型arrayClass
の配列の要素にアクセスするVarHandleを生成します。static MethodHandle
arrayLength(Class<?> arrayClass)
arraylength
バイトコードの場合と同様に、配列の長さを返すメソッド・ハンドルを生成します。static VarHandle
byteArrayViewVarHandle(Class<?> viewArrayClass, ByteOrder byteOrder)
byte[]
配列の要素にアクセスするVarHandleを生成し、int[]
やlong[]
などの異なるプリミティブ配列型であるかのように見せます。static VarHandle
byteBufferViewVarHandle(Class<?> viewArrayClass, ByteOrder byteOrder)
int[]
またはlong[]
など、byte
の要素にアクセスするVarHandleを生成します。これは、ByteBuffer
の要素と異なるプリミティブ・コンポーネント型の要素の配列であるかのように見えます。static MethodHandle
catchException(MethodHandle target, Class<? extends Throwable> exType, MethodHandle handler)
ターゲットのメソッド・ハンドルを例外ハンドラの内部で実行することによって、このターゲットを適応させるメソッド・ハンドルを作成します。static MethodHandle
collectArguments(MethodHandle target, int pos, MethodHandle filter)
ターゲット・メソッド・ハンドルを、フィルタ(別のメソッド・ハンドル)でその引数のサブシーケンスを前処理することにより、適応させます。static MethodHandle
constant(Class<?> type, Object value)
要求された戻り値の型を持ち、呼び出されるたびに指定された定数値を返すメソッド・ハンドルを生成します。static MethodHandle
countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body)
指定された回数の反復を実行するループを構築します。static MethodHandle
countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body)
一連の数値をカウントするループを構築します。static MethodHandle
doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred)
初期化子、本文、述語からdo-while
ループを構築します。static MethodHandle
dropArguments(MethodHandle target, int pos, Class<?>... valueTypes)
いくつかのダミー引数を破棄してから指定された別のtargetメソッド・ハンドルを呼び出すメソッド・ハンドルを生成します。static MethodHandle
dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes)
いくつかのダミー引数を破棄してから指定された別のtargetメソッド・ハンドルを呼び出すメソッド・ハンドルを生成します。static MethodHandle
dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos)
指定されたパラメータ型に一致するように、ターゲット・メソッド・ハンドルを適合させます。static MethodHandle
empty(MethodType type)
任意の引数を無視し、何もせず、戻り値の型に応じて適切な既定値を返す、リクエストされた型のメソッド・ハンドルを生成します。static MethodHandle
exactInvoker(MethodType type)
特殊なインボーカ・メソッド・ハンドルを生成します(これを使用すれば、指定された型の任意のメソッド・ハンドルを、invokeExact
を使用する場合と同様に呼び出すことができる)。static MethodHandle
explicitCastArguments(MethodHandle target, MethodType newType)
指定されたメソッド・ハンドルの型を新しい型に適応させるために、引数と戻り値の型の変換をペア単位で行うメソッド・ハンドルを生成します。static MethodHandle
filterArguments(MethodHandle target, int pos, MethodHandle... filters)
ターゲット・メソッド・ハンドルを適応させるため、その1つ以上の引数をそれぞれ固有の単項フィルタ関数を使って前処理したあと、前処理を行った各引数を対応するフィルタ関数の結果で置き換えてターゲットを呼び出します。static MethodHandle
filterReturnValue(MethodHandle target, MethodHandle filter)
ターゲット・メソッド・ハンドルを適応させるため、その戻り値(存在する場合)をフィルタ(別のメソッド・ハンドル)で後処理します。static MethodHandle
foldArguments(MethodHandle target, int pos, MethodHandle combiner)
指定された位置から開始し、前処理の結果でターゲットを呼び出し、折りたたまれた引数の直前の引数の元のシーケンスに挿入して、引数の一部を前処理することによって、ターゲット・メソッド・ハンドルを修正します。static MethodHandle
foldArguments(MethodHandle target, MethodHandle combiner)
ターゲット・メソッド・ハンドルを適応させるため、その引数のいくつかを前処理したあと、前処理の結果を元の一連の引数内に挿入してターゲットを呼び出します。static MethodHandle
guardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback)
テスト(boolean値のメソッド・ハンドル)で保護することでターゲット・メソッド・ハンドルを適応させるメソッド・ハンドルを作成します。static MethodHandle
identity(Class<?> type)
呼出し時に唯一の引数の値を返すメソッド・ハンドルを生成します。static MethodHandle
insertArguments(MethodHandle target, int pos, Object... values)
ターゲット・メソッド・ハンドルの呼出しの前に、1つ以上のバインド引数をメソッド・ハンドルに提供します。static MethodHandle
invoker(MethodType type)
特殊なインボーカ・メソッド・ハンドルを生成します(これを使用すれば、指定された型と互換性のある任意のメソッド・ハンドルを、invoke
を使用する場合と同様に呼び出すことができる)。static MethodHandle
iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body)
Iterator<T>
によって生成された値の範囲にあるループを構築します。static MethodHandles.Lookup
lookup()
呼出し元のすべてのサポートされるバイトコード動作をエミュレートするためのフル機能を持つルックアップ・オブジェクト
を返します。static MethodHandle
loop(MethodHandle[]... clauses)
各反復時に更新およびチェックされる複数のループ変数を持つループを表すメソッド・ハンドルを作成します。static MethodHandle
permuteArguments(MethodHandle target, MethodType newType, int... reorder)
引数の順序を変更することによって、指定されたメソッド・ハンドルの呼出し順序を新しい型に適応させるメソッド・ハンドルを生成します。static MethodHandles.Lookup
privateLookupIn(Class<?> targetClass, MethodHandles.Lookup caller)
「プライベート・アクセス」を含む、サポートされているすべてのバイトコード動作をエミュレートするために、ターゲット・クラスのlookup
オブジェクトを返します。static MethodHandles.Lookup
publicLookup()
最小の信頼レベルを持つルックアップ・オブジェクト
を返します。static <T extends Member>
TreflectAs(Class<T> expected, MethodHandle target)
直接メソッド・ハンドルの未チェックの解読を実行します。static MethodHandle
spreadInvoker(MethodType type, int leadingArgCount)
指定されたtype
の任意のメソッド・ハンドルを呼び出すメソッド・ハンドルを生成しますが、その際、指定された数の末尾の引数が単一の末尾のObject[]
配列で置き換えられます。static MethodHandle
throwException(Class<?> returnType, Class<? extends Throwable> exType)
指定されたexType
の例外をスローするメソッド・ハンドルを生成します。static MethodHandle
tryFinally(MethodHandle target, MethodHandle cleanup)
target
メソッドのハンドルをtry-finally
ブロックにラップすることによって処理するメソッド・ハンドルを作成します。static MethodHandle
varHandleExactInvoker(VarHandle.AccessMode accessMode, MethodType type)
関連付けられたアクセス・モードの型が指定された型と互換性のあるVarHandle上で、シグネチャ・ポリモーフィック・アクセス・モード・メソッドを呼び出すために使用できる特別な「呼び出しメソッドhandle」を生成します。static MethodHandle
varHandleInvoker(VarHandle.AccessMode accessMode, MethodType type)
関連付けられたアクセス・モードの型が指定された型と互換性のあるVarHandle上で、シグネチャ・ポリモーフィック・アクセス・モード・メソッドを呼び出すために使用できる特別な「呼び出しメソッドhandle」を生成します。static MethodHandle
whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body)
初期化子、本文、述語からwhile
ループを構築します。static MethodHandle
zero(Class<?> type)
呼び出されるたびにその型のデフォルト値を返すリクエストされた戻り値型の定数メソッド・ハンドルを生成します。
-
メソッドの詳細
-
lookup
public static MethodHandles.Lookup lookup()呼出し元のすべてのサポートされるバイトコード動作をエミュレートするためのフル機能を持つルックアップ・オブジェクト
を返します。 これらの機能には、コール元に対する「完全な権限アクセス」が含まれます。 ルックアップ・オブジェクトのファクトリ・メソッドは、呼出し元がバイトコードを介してアクセスするメンバー(protectedおよびprivateのフィールドおよびメソッドを含む)の直接メソッド・ハンドルを作成できます。 このルックアップ・オブジェクトは、信頼できるエージェントに委譲可能な1つの機能です。 信頼できないコードからアクセス可能な場所に格納しないでください。このメソッドは呼出し元依存です。つまり、呼出し元ごとに異なる値を返す可能性があります。
- 戻り値:
- 「完全な権限アクセス」を使用した、このメソッドのコール元の参照オブジェクト
-
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")
がチェックされ、正常に戻す必要があります。 - コール元参照オブジェクトには「完全な権限アクセス」が必要です。 具体的には、次のようになります。
- ターゲット・クラスは、プリミティブまたは配列クラスではなく、適切なクラスでなければなりません。 (したがって、
M2
は適切に定義されています。) - コール元モジュール
M1
がターゲット・モジュールM2
と異なる場合、次の両方がtrueである必要があります:
前述のいずれかのチェックに違反している場合、このメソッドは例外を出力して失敗します。
それ以外の場合、
M1
とM2
が同じモジュールである場合、このメソッドは「完全な権限アクセス」とnull
の以前の参照クラスを含むtargetClass
でLookup
を返します。それ以外の場合、
M1
とM2
は2つの異なるモジュールです。 このメソッドは、コール元のルックアップ・クラスを新しい前のルックアップ・クラスとして記録し、完全な権限アクセスからMODULE
アクセスを削除するtargetClass
上のLookup
を返します。- パラメータ:
targetClass
- ターゲット・クラスcaller
- 呼び出し元参照オブジェクト- 戻り値:
- ターゲット・クラスのルックアップ・オブジェクト。プライベート・アクセス
- 例外:
IllegalArgumentException
-targetClass
がプリミティブ・タイプ、voidまたは配列クラスの場合NullPointerException
-targetClass
またはcaller
がnull
の場合SecurityException
- セキュリティ・マネージャによって拒否された場合IllegalAccessException
- 上に指定した他のアクセス・チェックのいずれかが失敗した場合- 導入されたバージョン:
- 9
- 関連項目:
MethodHandles.Lookup.dropLookupMode(int)
, 「モジュール間参照」
- セキュリティ・マネージャが存在する場合は、
-
reflectAs
public static <T extends Member> T reflectAs(Class<T> expected, MethodHandle target)直接メソッド・ハンドルの未チェックの解読を実行します。 結果は、ユーザーがターゲット・メソッド・ハンドルを解決するのに十分な機能を持つルックアップ・オブジェクトを取得し、ターゲットでLookup.revealDirect
を呼び出してシンボリック参照を取得し、MethodHandleInfo.reflectAs
を呼び出してシンボリック参照をメンバーに解決したかのようになります。セキュリティ・マネージャが存在する場合は、その
checkPermission
メソッドがReflectPermission("suppressAccessChecks")
アクセス権で呼び出されます。- 型パラメータ:
T
- 結果に期待する型(Member
またはサブタイプ)- パラメータ:
target
- シンボリック参照コンポーネントに解決する直接メソッド・ハンドルexpected
- 期待する結果型T
を表すクラス・オブジェクト- 戻り値:
- メソッド、コンストラクタまたはフィールド・オブジクトへの参照
- 例外:
SecurityException
- 呼出し元にsetAccessible
を呼び出す権限が与えられていない場合NullPointerException
- どちらかの引数がnull
の場合IllegalArgumentException
- ターゲットが直接メソッド・ハンドルでない場合ClassCastException
- メンバーが期待される型でない場合- 導入されたバージョン:
- 1.8
-
arrayConstructor
public static MethodHandle arrayConstructor(Class<?> arrayClass) throws IllegalArgumentExceptionanewarray
バイトコードの場合と同様に、必要な型の配列を構築するメソッド・ハンドルを生成します。 メソッド・ハンドルの戻り値の型は配列型になります。 唯一の引数の型は、配列のサイズを指定するint
です。返されたメソッド・ハンドルが負の配列サイズで呼び出された場合は、
NegativeArraySizeException
がスローされます。- パラメータ:
arrayClass
- 配列の型- 戻り値:
- 指定された型の配列を作成できるメソッド・ハンドル
- 例外:
NullPointerException
- 引数がnull
の場合IllegalArgumentException
-arrayClass
が配列型でない場合- Java Virtual Machine仕様を参照してください:
-
6.5
anewarray
命令 - 導入されたバージョン:
- 9
- 関連項目:
Array.newInstance(Class, int)
-
arrayLength
public static MethodHandle arrayLength(Class<?> arrayClass) throws IllegalArgumentExceptionarraylength
バイトコードの場合と同様に、配列の長さを返すメソッド・ハンドルを生成します。 メソッド・ハンドルの型は戻り型としてint
を持ち、唯一の引数は配列型です。返されたメソッド・ハンドルが
null
配列参照で呼び出されると、NullPointerException
がスローされます。- パラメータ:
arrayClass
- 配列の型- 戻り値:
- 指定された配列型の配列の長さを取得できるメソッド・ハンドル
- 例外:
NullPointerException
- 引数がnull
の場合IllegalArgumentException
- arrayClassが配列型でない場合- Java Virtual Machine仕様を参照してください:
-
6.5
arraylength
命令 - 導入されたバージョン:
- 9
-
arrayElementGetter
public static MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentExceptionaaload
バイトコードの場合と同様に、配列の要素に対する読み取りアクセスを提供するメソッド・ハンドルを生成します。 メソッド・ハンドルの型に含まれる戻り値の型は、配列の要素の型になります。 その最初の引数は配列の型、2番目の引数はint
になります。返されたメソッド・ハンドルが呼び出されると、配列参照と配列インデックスがチェックされます。 配列リファレンスが
null
の場合はNullPointerException
がスローされ、インデックスが負の場合または配列の長さ以上の場合はArrayIndexOutOfBoundsException
がスローされます。- パラメータ:
arrayClass
- 配列の型- 戻り値:
- 指定された配列型から値をロードできるメソッド・ハンドル
- 例外:
NullPointerException
- 引数がnullの場合IllegalArgumentException
- arrayClassが配列型でない場合- Java Virtual Machine仕様を参照してください:
-
6.5
aaload
命令
-
arrayElementSetter
public static MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentExceptionastore
バイトコードの場合と同様に、配列の要素への書き込みアクセスを与えるメソッド・ハンドルを生成します。 このメソッド・ハンドルの型に含まれる戻り値の型は、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
以外の場合、数値アトミック更新アクセス・モードはサポートされていません。 - コンポーネント・タイプが
boolean
、byte
、short
、char
、int
または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 IllegalArgumentExceptionbyte[]
配列の要素にアクセスするVarHandleを生成し、int[]
やlong[]
などの異なるプリミティブ配列型であるかのように見せます。 VarHandle変数型はviewArrayClass
のコンポーネント型であり、座標型のリストは(byte[], int)
であり、int
座標型はbyte[]
配列へのインデックスである引数に対応します。 返されたVarHandleは、指定されたエンディアンに従って、viewArrayClass
のコンポーネント型の値との間でバイトを構成するbyte[]
配列のインデックスのバイトにアクセスします。サポートされるコンポーネント型(変数の型)は、
short
、char
、int
、long
、float
およびdouble
です。インデックスが
0
より小さい場合、またはbyte[]
配列の長さからT
のサイズ(バイト単位)を引いた値より大きい場合、特定のインデックスでバイトにアクセスすると、IndexOutOfBoundsException
になります。インデックスのバイトのアクセスは、
T
に対して、配列とインデックスに関連付けられている下位のメモリー・アドレスA
に対して、整列されていたり、位置がずれている可能性があります。 アクセスが整列していない場合、get
およびset
アクセス・モード以外のアクセスは、IllegalStateException
になります。 そのような場合、アトミック・アクセスは、A
のGCDとT
のサイズ(バイト単位)を分割する2の最大の累乗に関してのみ保証されます。 アクセスが整列されている場合、次のアクセス・モードがサポートされ、アトミック・アクセスをサポートすることが保証されています:- 32ビット・プラットフォーム上の
long
およびdouble
のアクセス・モードget
およびset
を除き、すべてのT
の読み取り/書き込みアクセス・モード。 int
、long
、float
またはdouble
のアトミック更新アクセス・モード。 (JDKの今後の主要なプラットフォーム・リリースは、現在サポートされていない特定のアクセス・モードに対して追加の型をサポートする可能性があります。)int
およびlong
の数値アトミック更新アクセス・モード。 (JDKの将来の主要なプラットフォーム・リリースは、現在サポートされていない特定のアクセス・モードに対して、追加の数値型をサポートする可能性があります。)int
とlong
のビット単位アトミック更新アクセス・モード。 (JDKの将来の主要なプラットフォーム・リリースは、現在サポートされていない特定のアクセス・モードに対して、追加の数値型をサポートする可能性があります。)
特定のアレイ上で動作することなく、
byte[]
配列に対して誤整列アクセス、したがってアトミック性の保証が決定される可能性があります。index
、T
が与えられ、それに対応するボックス化された型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
- 32ビット・プラットフォーム上の
-
byteBufferViewVarHandle
public static VarHandle byteBufferViewVarHandle(Class<?> viewArrayClass, ByteOrder byteOrder) throws IllegalArgumentExceptionint[]
またはlong[]
など、byte
の要素にアクセスするVarHandleを生成します。これは、ByteBuffer
の要素と異なるプリミティブ・コンポーネント型の要素の配列であるかのように見えます。 VarHandle変数型はviewArrayClass
のコンポーネント型であり、座標型のリストは(ByteBuffer, int)
であり、int
座標型はbyte[]
配列へのインデックスである引数に対応します。 返されたVarHandleは、指定されたエンディアンに従って、viewArrayClass
のコンポーネント型の値との間でバイトを構成するByteBuffer
のインデックスでバイトにアクセスします。サポートされるコンポーネント型(変数の型)は、
short
、char
、int
、long
、float
およびdouble
です。ByteBuffer
が読み取り専用の場合、アクセスは読み取りアクセス・モード以外の場合はReadOnlyBufferException
になります。インデックスが
0
より小さい場合、またはByteBuffer
制限からT
のサイズ(バイト単位)を引いた値より大きい場合、特定のインデックスでバイトにアクセスすると、IndexOutOfBoundsException
になります。インデックスのバイトのアクセスは、
T
の場合、ByteBuffer
およびindexに関連付けられている下位のメモリー・アドレスA
に対して、整列されていたり、位置がずれている可能性があります。 アクセスが整列していない場合、get
およびset
アクセス・モード以外のアクセスは、IllegalStateException
になります。 そのような場合、アトミック・アクセスは、A
のGCDとT
のサイズ(バイト単位)を分割する2の最大の累乗に関してのみ保証されます。 アクセスが整列されている場合、次のアクセス・モードがサポートされ、アトミック・アクセスをサポートすることが保証されています:- 32ビット・プラットフォーム上の
long
およびdouble
のアクセス・モードget
およびset
を除き、すべてのT
の読み取り/書き込みアクセス・モード。 int
、long
、float
またはdouble
のアトミック更新アクセス・モード。 (JDKの今後の主要なプラットフォーム・リリースは、現在サポートされていない特定のアクセス・モードに対して追加の型をサポートする可能性があります。)int
およびlong
の数値アトミック更新アクセス・モード。 (JDKの将来の主要なプラットフォーム・リリースは、現在サポートされていない特定のアクセス・モードに対して、追加の数値型をサポートする可能性があります。)int
とlong
のビット単位アトミック更新アクセス・モード。 (JDKの将来の主要なプラットフォーム・リリースは、現在サポートされていない特定のアクセス・モードに対して、追加の数値型をサポートする可能性があります。)
ByteBuffer
、bb
(直接的またはその他の方法で)、index
、T
に対して、整列されていないアクセス、したがってアトミック性の保証が決定され、対応するボックス化された型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
- 32ビット・プラットフォーム上の
-
spreadInvoker
public static MethodHandle spreadInvoker(MethodType type, int leadingArgCount)指定されたtype
の任意のメソッド・ハンドルを呼び出すメソッド・ハンドルを生成しますが、その際、指定された数の末尾の引数が単一の末尾のObject[]
配列で置き換えられます。 結果となるインボーカは、次の引数を持つメソッド・ハンドルです。- 単一の
MethodHandle
ターゲット - 0個以上の先頭の値(個数は
leadingArgCount
) - 末尾の引数を含む
Object[]
配列
インボーカがそのターゲットを呼び出す方法は、示された
type
を使用したinvoke
の呼出しに似ています。 つまりその動作は、ターゲットの型が指定されたtype
と完全に等しい場合はinvokeExact
のようになり、それ以外の場合は、asType
を使ってターゲットを必要なtype
に変換するような動作になります。返されるインボーカの型は、指定された
type
ではなく、最初のleadingArgCount
個を除くすべてのパラメータが単一のObject[]
型配列で置き換えられたものとなり、これが最後のパラメータになります。インボーカはそのターゲットを呼び出す前に、最後の配列を分配し、参照キャストを必要に応じて適用するほか、プリミティブ引数のアンボクシングやワイドニングを行います。 インボーカが呼び出されるときに、渡される配列引数が正しい数の要素を持たない場合、インボーカはターゲットを呼び出すかわりに
IllegalArgumentException
をスローします。このメソッドは次のコードと同等です(ただし、効率はおそらくこのメソッドのほうが高い)。
このメソッドでは、リフレクションやセキュリティに関する例外はスローされません。MethodHandle invoker = MethodHandles.invoker(type); int spreadArgCount = type.parameterCount() - leadingArgCount; invoker = invoker.asSpreader(Object[].class, spreadArgCount); return invoker;
- パラメータ:
type
- 目的となるターゲットの型leadingArgCount
- ターゲットに無変更で渡される固定引数の数- 戻り値:
- 指定された型の任意のメソッド・ハンドルの呼出しに適したメソッド・ハンドル
- 例外:
NullPointerException
-type
がnullである場合IllegalArgumentException
-leadingArgCount
が0からtype.parameterCount()
(含む)までの範囲でない場合、または結果のメソッド・ハンドルの型のパラメータ数が多すぎる場合
- 単一の
-
exactInvoker
public static MethodHandle exactInvoker(MethodType type)特殊なインボーカ・メソッド・ハンドルを生成します(これを使用すれば、指定された型の任意のメソッド・ハンドルを、invokeExact
を使用する場合と同様に呼び出すことができる)。 結果となるインボーカの型は、MethodHandle
型の追加の先頭の引数を1つ受け取る点を除けば、目的の型とまったく等しくなります。このメソッドは次のコードと同等です(ただし、効率はおそらくこのメソッドのほうが高い)。
publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
解説: インボーカ・メソッド・ハンドルは、未知の型のメソッド・ハンドル変数を操作する場合に役立つ可能性があります。 たとえば、メソッド・ハンドル変数
M
へのinvokeExact
呼出しをエミュレートするには、その型T
を抽出し、T
用のインボーカ・メソッドX
を検索し、インボーカ・メソッドをX.invoke(T, A...)
のように呼び出します。 (型T
が未知であるため、X.invokeExact
の呼出しは機能しない。) 分配や収集などの引数変換が必要な場合は、それらをインボーカX
に一度だけ適用しておけば、M
のさまざまなメソッド・ハンドル値(ただしX
の型と互換性があるものにかぎる)で再利用できます。(ノート: Core Reflection API経由でインボーカ・メソッドを使用することはできません。 宣言された
invokeExact
またはinvoke
メソッドでjava.lang.reflect.Method.invokeを呼び出そうとすると、UnsupportedOperationException
が発行されます。)このメソッドでは、リフレクションやセキュリティに関する例外はスローされません。
- パラメータ:
type
- 目的となるターゲットの型- 戻り値:
- 指定された型の任意のメソッド・ハンドルの呼出しに適したメソッド・ハンドル
- 例外:
IllegalArgumentException
- 結果のメソッド・ハンドルの型のパラメータ数が多すぎる場合
-
invoker
public static MethodHandle invoker(MethodType type)特殊なインボーカ・メソッド・ハンドルを生成します(これを使用すれば、指定された型と互換性のある任意のメソッド・ハンドルを、invoke
を使用する場合と同様に呼び出すことができる)。 結果となるインボーカの型は、MethodHandle
型の追加の先頭の引数を1つ受け取る点を除けば、目的の型とまったく等しくなります。ターゲットが期待される型と異なっている場合、インボーカはそのターゲットを呼び出す前に、
asType
の場合と同じように、参照キャストを必要に応じて適用するほか、プリミティブ値のボクシング、アンボクシング、またはワイドニングを行います。 同様に、戻り値も必要に応じて変換されます。 ターゲットが可変引数メソッド・ハンドルの場合は、やはりasType
の場合と同じように、必要な引数変換が行われます。このメソッドは次のコードと同等です(ただし、効率はおそらくこのメソッドのほうが高い)。
publicLookup().findVirtual(MethodHandle.class, "invoke", type)
ディスカッション: 一般的なメソッド型は、
Object
引数および戻り値のみを言及するものです。 そのような型のインボーカは、引数の数が汎用型と同じメソッド・ハンドルであれば任意のものを呼び出すことができます。(ノート: Core Reflection API経由でインボーカ・メソッドを使用することはできません。 宣言された
invokeExact
またはinvoke
メソッドでjava.lang.reflect.Method.invokeを呼び出そうとすると、UnsupportedOperationException
が発行されます。)このメソッドでは、リフレクションやセキュリティに関する例外はスローされません。
- パラメータ:
type
- 目的となるターゲットの型- 戻り値:
- 指定された型に変換可能な任意のメソッド・ハンドルの呼出しに適したメソッド・ハンドル
- 例外:
IllegalArgumentException
- 結果のメソッド・ハンドルの型のパラメータ数が多すぎる場合
-
varHandleExactInvoker
public static MethodHandle varHandleExactInvoker(VarHandle.AccessMode accessMode, MethodType type)関連付けられたアクセス・モードの型が指定された型と互換性のあるVarHandle上で、シグネチャ・ポリモーフィック・アクセス・モード・メソッドを呼び出すために使用できる特別な「呼び出しメソッドhandle」を生成します。 結果の呼び出し側の型は、型VarHandle
の追加の引き数を受け入れることを除いて、指定された型とまったく同じ型を持ちます。- パラメータ:
accessMode
- VarHandleアクセス・モードtype
- 目的となるターゲットの型- 戻り値:
- アクセス・モードの型が指定された型のVarHandleのアクセス・モード・メソッドを呼び出すのに適したメソッド・ハンドル。
- 導入されたバージョン:
- 9
-
varHandleInvoker
public static MethodHandle varHandleInvoker(VarHandle.AccessMode accessMode, MethodType type)関連付けられたアクセス・モードの型が指定された型と互換性のあるVarHandle上で、シグネチャ・ポリモーフィック・アクセス・モード・メソッドを呼び出すために使用できる特別な「呼び出しメソッドhandle」を生成します。 結果の呼び出し側の型は、型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
で行われる変換の前に、あるいはその代わりに、次のいずれかの変換が可能であれば適用されます(T0、T1は型)。- T0とT1が参照であり、T1がインタフェース型である場合は、型T0の値がキャストなしでT1として渡されます。 (インタフェースのこの扱いは、バイトコード・ベリファイアの使用法に従ったものです。)
- T0がbooleanでT1が別のプリミティブの場合、booleanがバイト値に変換されます(trueは1、falseは0)。 (この扱いは、バイトコード・ベリファイアの使用法に従ったものです。)
- T1がbooleanでT0が別のプリミティブの場合、Javaキャスト変換(JLS 5.5)によってT0がbyteに変換され、結果の下位ビットのテストが、
(x & 1)!= 0
と同様に行われます。 - T0とT1がboolean以外のプリミティブの場合、Javaキャスト変換(JLS 5.5)が適用されます。 (具体的には、ワイドニングやナローイングによってT0がT1に変換される。)
- T0が参照でT1がプリミティブの場合は、実行時にアンボクシング変換が適用されますが、そのあと、プリミティブ値に対してJavaキャスト変換(JLS 5.5)が行われる可能性があり、さらに下位ビットのテストによるbyteからbooleanへの変換が行われる可能性もあります。
- T0が参照でT1がプリミティブの場合、実行時に参照がnullであれば、値ゼロが導入されます。
- パラメータ:
target
- 引数の型を調整したあとに呼び出すメソッド・ハンドルnewType
- 新しいメソッド・ハンドルの期待される型- 戻り値:
- 必要な引数変換をすべて実行したあとでターゲットに委譲し、必要なあらゆる戻り値変換の手配も行うメソッド・ハンドル
- 例外:
NullPointerException
- どちらかの引数がnullの場合WrongMethodTypeException
- 変換できない場合- 関連項目:
MethodHandle.asType(java.lang.invoke.MethodType)
-
permuteArguments
public static MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder)引数の順序を変更することによって、指定されたメソッド・ハンドルの呼出し順序を新しい型に適応させるメソッド・ハンドルを生成します。 結果のメソッド・ハンドルが目的の新しい型と等しい型を報告することが、保証されます。指定された配列によって並べ替えが制御されます。 入力パラメータの数(値
newType.parameterCount()
)を#I
、出力パラメータの数(値target.type().parameterCount()
)を#O
とします。 このとき、並べ替え配列の長さは#O
、各要素は#I
より小さい負でない数でなければいけません。#O
より小さいすべてのN
について、N
番目の出力引数はI
番目の入力引数から取られます(I
はreorder[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
の場合
-
0
public static MethodHandle zero(Class<?> type)呼び出されるたびにその型のデフォルト値を返すリクエストされた戻り値型の定数メソッド・ハンドルを生成します。 結果の定数メソッド・ハンドルには副作用がありません。返されるメソッド・ハンドルは、
empty(methodType(type))
と等価です。 また、explicitCastArguments
はnull
をデフォルト値に変換するため、explicitCastArguments(constant(Object.class, null), methodType(type))
と同等です。- パラメータ:
type
- 目的のメソッド・ハンドルの期待される戻り値の型- 戻り値:
- 引数をとらず、指定された型のデフォルト値を返す定数メソッド・ハンドル(型がvoidの場合はvoid)
- 例外:
NullPointerException
- 引数がnullの場合- 導入されたバージョン:
- 9
- 関連項目:
constant(java.lang.Class<?>, java.lang.Object)
,empty(java.lang.invoke.MethodType)
,explicitCastArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)
-
empty
public static MethodHandle empty(MethodType type)任意の引数を無視し、何もせず、戻り値の型に応じて適切な既定値を返す、リクエストされた型のメソッド・ハンドルを生成します。 つまり、null
、またはvoid
のゼロ・プリミティブ値を返します。返されるメソッド・ハンドルは、
dropArguments(zero(type.returnType()), 0, type.parameterList())
と等価です。- APIのノート:
- 述部とターゲットが与えられれば、有用な"if-then"構成を
guardWithTest(pred, target, empty(target.type())
として生成することができます。 - パラメータ:
type
- 目的のメソッド・ハンドルの型- 戻り値:
- 与えられた戻り値の型のデフォルト値を返す、指定された型の定数メソッド・ハンドル
- 例外:
NullPointerException
- 引数がnullの場合- 導入されたバージョン:
- 9
- 関連項目:
zero(java.lang.Class<?>)
,constant(java.lang.Class<?>, java.lang.Object)
-
insertArguments
public static MethodHandle insertArguments(MethodHandle target, int pos, Object... values)ターゲット・メソッド・ハンドルの呼出しの前に、1つ以上のバインド引数をメソッド・ハンドルに提供します。 ターゲットの仮パラメータのうちで、バインド引数に対応しているものは、バインド・パラメータと呼ばれます。 バインド引数を保存した新しいメソッド・ハンドルを返します。 これは呼出し時に、すべての非バインド・パラメータに対する引数を受け取り、保存しておいた引数を対応するパラメータにバインドし、元のターゲットを呼び出します。新しいメソッド・ハンドルの型には、元のターゲットの型に含まれていたバインド・パラメータの型は含まれませんが、これは、新しいメソッド・ハンドルではもう、呼出し元がそれらの引数を指定する必要がないからです。
指定された引数のオブジェクトはそれぞれ、対応するバインド・パラメータの型に一致する必要があります。 バインド・パラメータの型がプリミティブの場合、引数のオブジェクトはラッパーである必要があり、オブジェクトがアンボクシングされてプリミティブ値が生成されます。
pos
引数によってバインドするパラメータが選択されます。 その範囲は0 - N-L (両端を含む)です。ここで、Nはターゲット・メソッド・ハンドルの引数長、Lは値配列の長さです。ノート: たとえ元のターゲット・メソッド・ハンドルがあったとしても、得られるアダプタは決して可変メソッド・ハンドルではありません。
- パラメータ:
target
- 引数を挿入したあとに呼び出すメソッド・ハンドルpos
- 引数の挿入位置(先頭の場合はゼロ)values
- 挿入する一連の引数- 戻り値:
- 追加の引数を挿入してから元のメソッド・ハンドルを呼び出すメソッド・ハンドル
- 例外:
NullPointerException
- ターゲットまたはvalues
配列がnullの場合IllegalArgumentException
- (@ code pos)が0
以下、N - L
より多く、N
がターゲット・メソッド・ハンドルの引数長さ、L
が値配列の長さである場合。ClassCastException
- 引数が対応するバウンド・パラメータ・タイプと一致しない場合。- 関連項目:
MethodHandle.bindTo(java.lang.Object)
-
dropArguments
public static MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes)いくつかのダミー引数を破棄してから指定された別のtargetメソッド・ハンドルを呼び出すメソッド・ハンドルを生成します。 新しいメソッド・ハンドルの型は、ターゲットの型とほぼ同じになりますが、指定された位置にダミー引数の型も含む点が異なります。pos
引数の範囲は0 - N (Nはターゲットの引数の数)になります。 ダミー引数は、pos
が0の場合はターゲットの実際の引数の前に追加され、pos
がNの場合は後ろに追加されます。例:
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の場合はターゲットの実際の引数の前に追加され、pos
がNの場合は後ろに追加されます。- 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
の呼び出しの結果は、P
とA
の型がdropArguments(MethodHandle, int, Class[])
のように挿入されたパラメータ型リストS..., P..., M..., A...
を持ちます。- 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
にtarget
が含まれない場合pos
。- 導入されたバージョン:
- 9
- ターゲット・ハンドルは、
-
filterArguments
public static MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters)ターゲット・メソッド・ハンドルを適応させるため、その1つ以上の引数をそれぞれ固有の単項フィルタ関数を使って前処理したあと、前処理を行った各引数を対応するフィルタ関数の結果で置き換えてターゲットを呼び出します。前処理は、
filters
配列の要素として指定された1つ以上のメソッド・ハンドルによって実行されます。 フィルタ配列の最初の要素がターゲットのpos
の位置の引数に対応する、といった関係がその後も順に続きます。 フィルタ関数は、左から右の順序で起動されます。配列内のnull引数はアイデンティティ関数とみなされ、対応する引数は変更されないままになります。 (nullでない要素が配列内に1つも存在しない場合は、元のターゲットが返されます。) 各フィルタはアダプタの対応する引数に適用されます。
フィルタ
F
がターゲットのN
番目の引数に適用される場合、F
は、ちょうど1つの引数を取るメソッド・ハンドルでなければいけません。 結果となる適応後のメソッド・ハンドル内では、F
の唯一の引数の型で、ターゲットの対応する引数の型が置き換えられます。F
の戻り値の型は、ターゲットの対応するパラメータの型と同一でなければいけません。ターゲット内の引数位置に対応しない
filters
の要素(nullの場合がある)が存在する場合は、エラーになります。例:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); MethodHandle upcase = lookup().findVirtual(String.class, "toUpperCase", methodType(String.class)); assertEquals("xy", (String) cat.invokeExact("x", "y")); MethodHandle f0 = filterArguments(cat, 0, upcase); assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy MethodHandle f1 = filterArguments(cat, 1, upcase); assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY MethodHandle f2 = filterArguments(cat, 0, upcase, upcase); assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
結果のアダプタの擬似コードは次のとおりです。 コードでは、
T
は、target
とその結果のアダプタの両方の戻り型を示します。P
/p
およびB
/b
は、それぞれフィルタ位置pos
の前および後のパラメータおよび引数の型および値を表す。A[i]
/a[i]
は、フィルタリングされたパラメータと引数の型と値を表します。filter[i]
ハンドルの戻り値の型も表します。 後者は、型V[i]
の引数v[i]
を受け取ります。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.length
がtarget.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
は、V
がvoid
でないかぎり、それぞれ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からターゲットの引数カウントの間(含む)にない場合、または結果のメソッド・ハンドルの型のパラメータ数が多すぎる場合- 関連項目:
foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle)
、filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...)
、filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle)
-
filterReturnValue
public static MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter)ターゲット・メソッド・ハンドルを適応させるため、その戻り値(存在する場合)をフィルタ(別のメソッド・ハンドル)で後処理します。 フィルタの結果がアダプタから返されます。ターゲットが値を返す場合、フィルタはその値を唯一の引数として受け入れる必要があります。 ターゲットがvoidを返す場合、フィルタは引数を一切受け入れてはいけません。
結果となる適応後のメソッド・ハンドル内では、フィルタの戻り値の型でターゲットの戻り値の型が置き換えられます。 フィルタの引数の型(存在する場合)は、ターゲットの戻り値の型と同一でなければいけません。
例:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); MethodHandle length = lookup().findVirtual(String.class, "length", methodType(int.class)); System.out.println((String) cat.invokeExact("x", "y")); // xy MethodHandle f0 = filterReturnValue(cat, length); System.out.println((int) f0.invokeExact("x", "y")); // 2
結果のアダプタの擬似コードは次のとおりです。 コードでは、
T
/t
はtarget
の結果の型と値を表します。V
、filter
の結果型。A
/a
、target
のパラメータと引数の型と値、および結果のアダプタ。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
のパラメータと引数の型と値を表します。V
もcombiner
の結果型です。A
/a
は、折り畳み位置でのN
パラメータと引数の型と値を示します。B
/b
は、target
のパラメータと引数のタイプと値を表し、折り返されたパラメータと引数に続くものです。// there are N arguments in A... T target(V, A[N]..., B...); V combiner(A...); T adapter(A... a, B... b) { V v = combiner(a...); return target(v, a..., b...); } // and if the combiner has a void return: T target2(A[N]..., B...); void combiner2(A...); T adapter2(A... a, B... b) { combiner2(a...); return target2(a..., b...); }
ノート: たとえ元のターゲット・メソッド・ハンドルがあったとしても、得られるアダプタは決して可変メソッド・ハンドルではありません。
- パラメータ:
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
のパラメータと引数の型と値を表します。V
もcombiner
の結果型です。A
/a
は、折り畳み位置でのN
パラメータと引数の型と値を示します。Z
/z
とB
/b
は、それぞれpos
で始まる折り畳まれたパラメータと引数の前後にあるtarget
パラメータと引数の型と値を表します。// there are N arguments in A... T target(Z..., V, A[N]..., B...); V combiner(A...); T adapter(Z... z, A... a, B... b) { V v = combiner(a...); return target(z..., v, a..., b...); } // and if the combiner has a void return: T target2(Z..., A[N]..., B...); void combiner2(A...); T adapter2(Z... z, A... a, B... b) { combiner2(a...); return target2(z..., a..., b...); }
ノート: たとえ元のターゲット・メソッド・ハンドルがあったとしても、得られるアダプタは決して可変メソッド・ハンドルではありません。
- パラメータ:
target
- 引数を結合したあとで呼び出すメソッド・ハンドルpos
- 折りたたみを開始し、折り畳み結果を挿入する位置。これが0
の場合、効果はfoldArguments(MethodHandle, MethodHandle)
と同じです。combiner
- 入力引数に対して最初に呼び出すメソッド・ハンドル- 戻り値:
- 指定された引数フォールディング・ロジックが組み込まれたメソッド・ハンドル
- 例外:
NullPointerException
- どちらかの引数がnullの場合IllegalArgumentException
- 以下の2つの条件のいずれかが成り立つ: (1)combiner
戻り型がvoid
ではなく、ターゲット・シグネチャの位置pos
の引数の型と同じではありません。(2)ターゲット・シグネチャ(combiner
戻り値の型と一致するものをスキップ)のpos
の位置にあるN
引数の型は、引数の型combiner
と同じではありません。- 導入されたバージョン:
- 9
- 関連項目:
foldArguments(MethodHandle, MethodHandle)
-
guardWithTest
public static MethodHandle guardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback)テスト(boolean値のメソッド・ハンドル)で保護することでターゲット・メソッド・ハンドルを適応させるメソッド・ハンドルを作成します。 保護に失敗した場合は、代わりにフォール・バック・ハンドルが呼び出されます。 テストの戻り値の型がbooleanでなければいけない点と、テストの引数の数がほかの2つのメソッド・ハンドルより少なくてもかまわないという点を除き、3つのメソッド・ハンドルの対応する引数と戻り値の型はすべて同じである必要があります。結果のアダプタの擬似コードは次のとおりです。 コードでは、
T
は、3つのハンドルの統一された結果の型を表します。A
/a
、test
で消費される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
が指定された例外の型を受け入れない場合、またはメソッド・ハンドルの型に含まれる戻り値の型と対応するパラメータが一致しない場合- 関連項目:
tryFinally(MethodHandle, MethodHandle)
-
throwException
public static MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType)指定されたexType
の例外をスローするメソッド・ハンドルを生成します。 メソッド・ハンドルは、exType
の単一の引数を受け入れ、それを即時に例外としてスローします。 メソッド型では形式上、returnType
の戻り値が指定されます。 戻り値の型は、どのようなものでもかまいません。メソッド・ハンドルが通常どおりに戻ることは決してないので、メソッド・ハンドルの動作には何の影響もありません。- パラメータ:
returnType
- 期待するメソッド・ハンドルの戻り型exType
- 期待するメソッド・ハンドルのパラメータ型- 戻り値:
- 指定された例外をスローできるメソッド・ハンドル
- 例外:
NullPointerException
- どちらかの引数がnullの場合
-
loop
public static MethodHandle loop(MethodHandle[]... clauses)各反復時に更新およびチェックされる複数のループ変数を持つループを表すメソッド・ハンドルを作成します。 述語の1つのためにループが終了すると、対応するファイナライザが実行され、結果のハンドルの戻り値であるループ結果が送られます。直感的に、すべてのループは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*)
)の任意のプレフィクスを表現します。 その表記法では、init関数のパラメータ・リストの一般形式は(A*)
であり、非init関数のパラメータ・リストの一般形式は(V*)
または(V... A*)
です。チェック句の構造: 一連の句がある場合、ループのすべての部分を接続するために多数のチェックと調整が行われます。 それらは以下のステップで詳細に説明されています。 これらのステップでは、必要な制約がループ・コンビネータへの入力によって満たされない場合、単語のあらゆる出現は、
IllegalArgumentException
がスローされる場所に対応する必要があります。効果的に同一の配列:
A
とB
が同一である場合、またはA
がより短く、適切なプレフィクスB
と同一である場合、パラメータ・リストA
は、別のパラメータ・リストB
に対して効果的に同一となるように定義されています。 パラメータ・リストの順序付けられていないセットについて言えば、セットが最長リストを含み、セットのすべてのメンバーがその最長リストと事実上同一である場合、セットは全体として"効果的に同一"であると言う。 たとえば、(V*)
という形式の型シーケンスのセットは事実上同一であり、(V... A*)
という形式のシーケンスが追加される場合も同じです。ステップ0: 句の構造を決定します。
- 句(型
MethodHandle[][]
の)は非null
で、少なくとも1つの要素を含んでいなければなりません。 - 句の配列には、
null
または4つの要素より長いサブ配列を含めることはできません。 - 4つの要素よりも短い句は、
null
要素によって長さ4にパッディングされているかのように扱われます。 パディングは配列に要素を追加することによって行われます。 - すべての
null
を持つ句は無視されます。 - 各句は、"init"、"step"、"pred"、および"fini"という4つの関数のタプルとして扱われます。
ステップ1A: 繰り返し変数の型
(V...)
を決定します。- 各句の繰り返し変数の型は、句のinitおよびstepの戻り値の型を使用して決定されます。
- 両方の関数を省略すると、対応する句(
void
がその型を示すために使用されます。)の反復変数はありません。 そのうちの1つを省略すると、もう1つの戻り値の型は句の反復変数型を定義します。 両方が指定された場合、共通の戻り値の型(彼らは同一でなければならない)は句の反復変数型を定義します。 void
のすべての出現を省略して、戻り値の型(in句の順)のリストを作成します。- この型のリストは、"反復変数型" (
(V...)
)と呼ばれます。
ステップ1B: ループ・パラメータ
(A...)
を決定します。- init関数のパラメータ・リスト(これらは
(A*)
の形式です)を調べて収集します。 - 反復変数の型を削除した後、step、pred、およびfiniパラメータ・リストのサフィクスを調べて収集します。 (彼らは形式
(V... A*)
を持っている必要があります。(A*)
部品のみを回収してください。) - すべての反復変数型で始まらないstep、pred、およびfiniパラメータ・リストからサフィクスを収集しないでください。 (これらのタイプは、すべての条項関数タイプとともにステップ2でチェックインされます。)
- 省略された句の関数は無視されます。 (同様に、空のパラメータ・リストを持つとみなされます。)
- すべての収集されたパラメータ・リストは、実質的に同一でなければなりません。
- 最も長いパラメータ・リスト(必然的にユニークです)は、"外部パラメータ・リスト" (
(A...)
)と呼ばれます。 - このようなパラメータ・リストがない場合、外部パラメータ・リストは空のシーケンスとみなされます。
- 反復変数型とそれに続く外部パラメータ型の組み合わせリストは、"内部パラメータ・リスト"と呼ばれます。
ステップ1C: ループ戻り値の型を決定します。
- 省略されたfini関数を無視して、fini関数の戻り値の型を調べます。
- fini関数がない場合、ループの戻り値の型は
void
です。 - それ以外の場合は、fini関数(戻り値の型は同じでなければならない)の共通戻り型
R
がループ戻り型を定義します。
ステップ1D: その他の型を確認してください。
- 少なくとも1つの省略されていないpred関数が存在する必要があります。
- 省略されていないすべてのpred関数には、
boolean
戻り型が必要です。
ステップ2: パラメータ・リストを決定します。
- 結果のループ・ハンドルのパラメータ・リストは、外部パラメータ・リスト
(A...)
になります。 - init関数のパラメータ・リストは、外部パラメータ・リストに合わせて調整されます。 (パラメータ・リストは既にこのリストと実質的に同じであることに注意してください。)
- 初期化されていない非初期化(ステップ、プレ、フィニ)関数のパラメータ・リストは、内部パラメータ・リスト
(V... A...)
と実質的に同一でなければなりません。
ステップ3: 省略された関数を入力します。
- init関数が省略されている場合は、句の反復変数型に「デフォルト値」を使用します。
- ステップ関数を省略した場合は、節の反復変数型の「アイデンティティ関数」を使用します。先行する句の非
void
反復変数のアイデンティティ関数パラメータの前に、削除された引数パラメータを挿入します。 (これにより、ループ変数がローカル・ループ不変になります。) - pred関数を省略した場合は、定数
true
関数を使用してください。 (これは、この句が関係する限り、ループを続けるでしょう。 そのような場合、対応するfini関数に到達できないことに注意してください。) - fini関数が省略されている場合は、ループ戻り型として「デフォルト値」を使用します。
ステップ4: 欠落しているパラメータのタイプを入力します。
- この時点で、すべてのinit関数のパラメータ・リストは、外部パラメータ・リスト
(A...)
と実質的に同じですが、いくつかのリストは短くてもかまいません。 短いパラメータ・リストを持つすべてのinit関数に対して、リストの最後を埋めます。 - この時点で、非init関数の各パラメータ・リストは、内部パラメータ・リスト
(V... A...)
と実質的に同じですが、リストの中にはより短いものがあります。 短いパラメータ・リストを持つすべての非init関数に対して、リストの末尾を埋めます。 - 引数リストは「未使用の末尾の引数を削除」によって埋められます。
最終的な観察。
- これらのステップの後、省略された関数と引数を指定することによって、すべての句が調整されました。
- すべてのinit関数は、共通のパラメータ型リスト
(A...)
を持っています。これは最終ループ・ハンドルにもあります。 - すべてのfini関数には共通の戻り型
R
があり、最終ループ・ハンドルにもこの型があります。 - すべての非初期化関数は、(non-
void
)反復変数V
とループ・パラメータのあとに共通のパラメータ型リスト(V... A...)
を持ちます。 - init関数とstep関数の各ペアは、戻り値の型
V
で一致します。 - 各非初期化関数は、すべての反復変数の現在の値
(v...)
を観測することができます。 - すべての関数は、すべてのループ・パラメータの入力値
(a...)
を観測できます。
Example. 上記のステップ1Aの結果、
loop
コンビネータは次のプロパティを持ちます:N
がn = 1..N
でCn = {null, Sn, Pn}
を指定すると仮定します。- 述語ハンドル
Pn
がnull
であるか、パラメータがないとします。 (1つのPn
は、非null
でなければなりません。) - ステップ・ハンドル
Sn
が、いくつかの定数X>=N
に対して(B1..BX)Rn
のシグネチャを持つとします。 Q
が非空白型のRn
の数であり、(V1...VQ)
がそれらの型のシーケンスであるとします。n = 1..min(X,Q)
のVn == Bn
でなければなりません。- パラメータ型
Vn
は、ループ・ローカル状態要素(V...)
として解釈されます。 - 残りのすべての型
BQ+1..BX
(Q<X
の場合)は、結果のループ・ハンドル・パラメータ型(A...)
を決定します。
(A...)
はステップ関数から導出されました。これは、ループ計算の大部分がステップで発生した場合に当然です。 いくつかのループでは、計算の負担がpred関数で最も重くなる可能性があるため、pred関数はループ・パラメータ値を受け入れる必要があります。 複雑な出口ロジックを持つループの場合、fini関数はループ・パラメータを受け入れる必要があり、同様に複雑な入口ロジックを持つループの場合、init関数には余分なパラメータが必要です。 このような理由から、これらのパラメータを決定するためのルールは、すべての句部分にわたって可能な限り対称です。 一般に、ループ・パラメータはループ全体にわたって共通の不変値として機能し、反復変数は一般的なバリアント値として機能し、内部ループ不変の一時変数として(ステップ機能がない場合)として機能します。ループ実行。
- ループが呼び出されると、ループ入力値はすべての句機能に渡されるようにローカルに保存されます。 これらのローカルはループ不変です。
- 各init関数は、(外部引数
(a...)
を渡します。)の句の順番で実行され、非void
の値は(反復変数として(v...)
)ローカルに保存されます。 これらのローカルの人々は、ループ変化(上記のように、ステップが同一性機能として動作しない限り)になります。 - すべての関数実行(init関数を除く)には、
(v...)
(in句の順)以外のvoid
反復値(v...)
と内部ループ入力(a...)
(引数順に)からなる内部パラメータ・リストが渡されます。 - 次に、pred関数が
false
を返すまで、stepおよびpred関数が句の順(前の一歩)で実行されます。 - ステップ関数呼び出しからの非
void
結果は、ループ変数のシーケンス(v...)
の対応する値を更新するために使用されます。 更新された値は、後続のすべての関数呼び出しでただちに表示されます。 - pred関数が
false
を返した場合は、対応するfini関数が呼び出され、結果の値(型R
の)がループ全体から返されます。 - すべてのpred関数が常にtrueを返す場合、fini関数は呼び出されず、例外をスローする以外はループを終了できません。
使用上のヒント。
- 各ステップ関数はループ変数のallの現在の値を受け取りますが、時にはステップ関数はそれ自身の変数の現在の値を観測するだけです。 その場合、ステップ関数は明示的に「前のすべてのループ変数を削除」を必要とするかもしれません。 これには、型を
dropArguments(step, 0, V0.class, ...)
のような式で記述する必要があります。 - ループ変数は変更する必要はありません。ループ不変である可能性があります。 句は、step、pred、またはfini関数を持たない適切なinit関数によってループ不変式を作成することができます。 これは、着信ループ引数を隣接するループ変数のステップまたはpred関数に"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(MethodHandle, MethodHandle, MethodHandle)
,doWhileLoop(MethodHandle, MethodHandle, MethodHandle)
,countedLoop(MethodHandle, MethodHandle, MethodHandle)
,iteratedLoop(MethodHandle, MethodHandle, MethodHandle)
- init: ループが実行される前に、型
-
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
という名前に割り当て、void
型V
がパラメータ・リストから静かに削除され、(A...)V
を残していることを理解して(V A...)V
を記述します。)- 本文のパラメータ・リスト
(V A...)
は、「内部パラメータ・リスト」と呼ばれます。 他のループ部分のパラメータ・リストを制約します。 - 反復変数型
V
が内部パラメータ・リストから削除された場合、結果として得られる短いリスト(A...)
は「外部パラメータ・リスト」と呼ばれます。 - 本文戻り型
V
(非void
の場合)は、ループの追加の状態変数の型を決定します。 本文は、この型の値を受け入れて返す必要があります。V
。 init
が非null
の場合、戻り型はV
でなければなりません。 そのパラメータ・リスト(いくつかの「フォーム(A*)
」)は、外部パラメータ・リスト(A...)
に対して「効果的に同一」でなければなりません。init
がnull
の場合、ループ変数は「デフォルト値」に初期化されます。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
またはbody
がnull
の場合。- 導入されたバージョン:
- 9
- 関連項目:
loop(MethodHandle[][])
,doWhileLoop(MethodHandle, MethodHandle, MethodHandle)
-
doWhileLoop
public static MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred)初期化子、本文、述語からdo-while
ループを構築します。 これは「ジェネリック・ループ・コンビネータ」の便利なラッパーです。pred
ハンドルはループ条件を記述します。body
、その本文。 このメソッドで得られたループは、各反復で最初にその本文を実行し、次に述語を評価します。 本文の実行後、述部がfalse
と評価されると、ループは終了します。init
ハンドルは、追加のオプションのループ・ローカル変数の初期値を記述します。 各反復で、このループ・ローカル変数が存在する場合、変数はbody
に渡され、その呼び出しから返された値で更新されます。 ループ実行の結果は、追加のループ・ローカル変数(存在する場合)の最終値になります。これらの引数ハンドルには、次の規則があります:
body
ハンドルはnull
であってはなりません。その型は、(V A...)V
の形式でなければなりません。ここで、V
は非void
です。そうでなければ(A...)void
です。 (void
の場合、型void
をV
という名前に割り当て、void
型V
がパラメータ・リストから静かに削除され、(A...)V
を残していることを理解して(V A...)V
を記述します。)- 本文のパラメータ・リスト
(V A...)
は、「内部パラメータ・リスト」と呼ばれます。 他のループ部分のパラメータ・リストを制約します。 - 反復変数型
V
が内部パラメータ・リストから削除された場合、結果として得られる短いリスト(A...)
は「外部パラメータ・リスト」と呼ばれます。 - 本文戻り型
V
(非void
の場合)は、ループの追加の状態変数の型を決定します。 本文は、この型の値を受け入れて返す必要があります。V
。 init
が非null
の場合、戻り型はV
でなければなりません。 そのパラメータ・リスト(いくつかの「フォーム(A*)
」)は、外部パラメータ・リスト(A...)
に対して「効果的に同一」でなければなりません。init
がnull
の場合、ループ変数は「デフォルト値」に初期化されます。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
またはbody
がnull
の場合。- 導入されたバージョン:
- 9
- 関連項目:
loop(MethodHandle[][])
,whileLoop(MethodHandle, MethodHandle, MethodHandle)
-
countedLoop
public static MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body)指定された回数の反復を実行するループを構築します。 これは「ジェネリック・ループ・コンビネータ」の便利なラッパーです。反復回数は、
iterations
ハンドル評価結果によって決まります。 ループ・カウンタi
は、型int
の余分なループ反復変数です。 0に初期化され、各反復で1ずつインクリメントされます。body
ハンドルが非void
型V
を戻す場合、その型の先頭ループ反復変数も存在します。 この変数は、オプションのinit
ハンドルを使用して、または型V
の「デフォルト値」(ハンドルがnull
の場合)を使用して初期化されます。各反復では、反復変数が
body
ハンドルの呼び出しに渡されます。 本文(型V
の)から返された非void
値は、先頭の反復変数を更新します。 ループ・ハンドル実行の結果は、その変数(V
変数がない場合はvoid
)の最後のV
値になります。引き数ハンドルには次の規則があります:
iterations
ハンドルはnull
であってはならず、パラメータ型リストでここではI
と呼ばれる型int
を返す必要があります。body
ハンドルはnull
であってはなりません。その型は、(V I A...)V
の形式でなければなりません。ここで、V
は非void
です。そうでなければ(I A...)void
です。 (void
の場合、型void
をV
という名前に割り当て、void
型V
がパラメータ・リストから静かに削除され、(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...)
に対して「効果的に同一」でなければなりません。init
がnull
の場合、ループ変数は「デフォルト値」に初期化されます。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のノート:
- 完全に適合する本文メソッドの例:
最も単純な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, String init) { return "na " + v; } // assume MH_step is a handle to the method above MethodHandle fit13 = MethodHandles.constant(int.class, 13); MethodHandle start = MethodHandles.identity(String.class); MethodHandle loop = MethodHandles.countedLoop(fit13, start, MH_step); assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!"));
反復回数、追加する文字列、ループ・パラメータとして追加する文字列を処理する例:// String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s; // => a variation on a well known theme static String step(String v, int counter ) { return "na " + v; } // assume MH_step is a handle to the method above MethodHandle count = MethodHandles.dropArguments(MethodHandles.identity(int.class), 1, String.class); MethodHandle start = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0, int.class); MethodHandle loop = MethodHandles.countedLoop(count, start, MH_step); // (v, i) -> "na " + v assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke(13, "Lambdaman!"));
ループ型を強制するための// String s = "Lambdaman!", t = "na"; for (int i = 0; i < 13; ++i) { s = t + " " + s; } return s; // => a variation on a well known theme static String step(String v, int counter, int iterations_, String pre, String start_) { return pre + " " + v; } // assume MH_step is a handle to the method above MethodHandle count = MethodHandles.identity(int.class); MethodHandle start = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0, int.class, String.class); MethodHandle loop = MethodHandles.countedLoop(count, start, MH_step); // (v, i, _, pre, _) -> pre + " " + v assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke(13, "na", "Lambdaman!"));
dropArgumentsToMatch(MethodHandle, int, List, int)
の使用例を示す例:
このメソッドの実装は、次のように表現できます:// String s = "Lambdaman!", t = "na"; for (int i = 0; i < 13; ++i) { s = t + " " + s; } return s; // => a variation on a well known theme static String step(String v, int counter, String pre) { return pre + " " + v; } // assume MH_step is a handle to the method above MethodType loopType = methodType(String.class, String.class, int.class, String.class); MethodHandle count = MethodHandles.dropArgumentsToMatch(MethodHandles.identity(int.class), 0, loopType.parameterList(), 1); MethodHandle start = MethodHandles.dropArgumentsToMatch(MethodHandles.identity(String.class), 0, loopType.parameterList(), 2); MethodHandle body = MethodHandles.dropArgumentsToMatch(MH_step, 2, loopType.parameterList(), 0); MethodHandle loop = MethodHandles.countedLoop(count, start, body); // (v, i, pre, _, _) -> pre + " " + v assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("na", 13, "Lambdaman!"));
MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body) { return countedLoop(empty(iterations.type()), iterations, init, body); }
- パラメータ:
iterations
- このループが実行する反復回数を返す非null
ハンドル。 ハンドル結果の型はint
でなければなりません。 他の制約については上記を参照してください。init
- ループ変数の初期値を提供するオプションの初期化子。 デフォルトの初期値を意味するnull
かもしれません。 他の制約については上記を参照してください。body
- ループの本文ですが、null
ではありません。 標準ケース(詳細は上記を参照)でループ・パラメータと結果型を制御します。 それは、それ自身のリターン型(非空白の場合)とint
パラメータ(カウンタのために)を受け入れなければならず、任意の数の追加型を受け入れることができます。 他の制約については上記を参照してください。- 戻り値:
- ループを表すメソッド・ハンドル。
- 例外:
NullPointerException
-iterations
またはbody
ハンドルのいずれかがnull
の場合。IllegalArgumentException
- 上記で定式化された規則に違反する場合。- 導入されたバージョン:
- 9
- 関連項目:
countedLoop(MethodHandle, MethodHandle, MethodHandle, MethodHandle)
-
countedLoop
public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body)一連の数値をカウントするループを構築します。 これは「ジェネリック・ループ・コンビネータ」の便利なラッパーです。ループ・カウンタ
i
は、型int
のループ反復変数です。start
およびend
ハンドルは、ループ・カウンタの開始(inclusive)および終了(exclusive)値を決定します。 ループ・カウンタは、start
ハンドルの評価から返されたint
値に初期化され、ステップ幅1でend
(exclusively)から返された値に実行されます。body
ハンドルが非void
型V
を戻す場合、その型の先頭ループ反復変数も存在します。 この変数は、オプションのinit
ハンドルを使用して、または型V
の「デフォルト値」(ハンドルがnull
の場合)を使用して初期化されます。各反復では、反復変数が
body
ハンドルの呼び出しに渡されます。 本文(型V
の)から返された非void
値は、先頭の反復変数を更新します。 ループ・ハンドル実行の結果は、その変数(V
変数がない場合はvoid
)の最後のV
値になります。引き数ハンドルには次の規則があります:
start
およびend
ハンドルはnull
であってはいけません。両方とも、共通型int
(I
)をパラメータ型リストで戻す必要があります。body
ハンドルはnull
であってはなりません。その型は、(V I A...)V
の形式でなければなりません。ここで、V
は非void
です。そうでなければ(I A...)void
です。 (void
の場合、型void
をV
という名前に割り当て、void
型V
がパラメータ・リストから静かに削除され、(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...)
に対して「効果的に同一」でなければなりません。init
がnull
の場合、ループ変数は「デフォルト値」に初期化されます。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
-int
でなければならないループ・カウンタの開始値を返すための非null
ハンドル。 他の制約については上記を参照してください。end
- ループ・カウンタ(ループはend-1
に実行されます)の終了値を返す非null
ハンドル。 結果の型はint
でなければなりません。 他の制約については上記を参照してください。init
- ループ変数の初期値を提供するオプションの初期化子。 デフォルトの初期値を意味するnull
かもしれません。 他の制約については上記を参照してください。body
- ループの本文ですが、null
ではありません。 標準ケース(詳細は上記を参照)でループ・パラメータと結果型を制御します。 それは、それ自身のリターン型(非空白の場合)とint
パラメータ(カウンタのために)を受け入れなければならず、任意の数の追加型を受け入れることができます。 他の制約については上記を参照してください。- 戻り値:
- ループを表すメソッド・ハンドル。
- 例外:
NullPointerException
-start
、end
、またはbody
ハンドルのいずれかがnull
である場合。IllegalArgumentException
- 上記で定式化された規則に違反する場合。- 導入されたバージョン:
- 9
- 関連項目:
countedLoop(MethodHandle, MethodHandle, MethodHandle)
-
iteratedLoop
public static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body)Iterator<T>
によって生成された値の範囲にあるループを構築します。 これは「ジェネリック・ループ・コンビネータ」の便利なラッパーです。イテレータ自体は、
iterator
ハンドルの評価によって決定されます。 生成される各値は、型T
のループ反復変数に格納されます。body
ハンドルが非void
型V
を戻す場合、その型の先頭ループ反復変数も存在します。 この変数は、オプションのinit
ハンドルを使用して、または型V
の「デフォルト値」(ハンドルがnull
の場合)を使用して初期化されます。各反復では、反復変数が
body
ハンドルの呼び出しに渡されます。 本文(型V
の)から返された非void
値は、先頭の反復変数を更新します。 ループ・ハンドル実行の結果は、その変数(V
変数がない場合はvoid
)の最後のV
値になります。引き数ハンドルには次の規則があります:
body
ハンドルはnull
であってはなりません。その型は、(V T A...)V
の形式でなければなりません。ここで、V
は非void
です。そうでなければ(T A...)void
です。 (void
の場合、型void
をV
という名前に割り当て、void
型V
がパラメータ・リストから静かに削除され、(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...)
に対して「効果的に同一」でなければなりません。init
がnull
の場合、ループ変数は「デフォルト値」に初期化されます。iterator
ハンドルがnull
以外の場合は、戻り型java.util.Iterator
またはそのサブ型を持たなければなりません。 ループが実行されたときに生成されるイテレータは、T
型に変換可能な値を生成すると見なされます。- 非
null
(いくつかの形式の(A*)
)であるiterator
のパラメータ・リストは、外部パラメータ・リスト(A...)
と実質的に同一でなければなりません。 iterator
がnull
の場合、デフォルトではIterable.iterator()
のように動作するメソッド・ハンドルになります。 この場合、内部パラメータ・リスト(V T A...)
には少なくとも1つのA
型が必要です。また、デフォルト・イテレータ・ハンドル・パラメータは、asType
変換メソッドの場合と同様に、先頭のA
型を受け入れるように調整されます。 先頭のA
型は、Iterable
またはそのサブ型でなければなりません。 この変換ステップは、ループ構築時に実行され、WrongMethodTypeException
を送出してはなりません。
型
T
は、プリミティブでも参照でもよい。 型ハンドルIterator<T>
は、メソッド・ハンドル表現で生の型Iterator
に消去されるので、iteratedLoop
コンビネータは、body
の先頭引数型を、asType
変換メソッドの場合と同様にObject
に調整します。 したがって、ループが実行されるときに間違った型のイテレータが表示された場合、MethodHandle.asType(MethodType)
によって実行される動的変換の結果として実行時例外が発生することがあります。結果のループ・ハンドルの結果の型とパラメータのシグネチャは、次のように決定されます:
- ループ・ハンドルの結果型は、本文の結果型
V
です。 - ループ・ハンドル・パラメータ型は、外部パラメータ・リストから、型
(A...)
です。
結果のループ・ハンドルの疑似コードを次に示します。 コードでは、
V
/v
は、ループ変数の型/値とループの結果型を表します。T
/t
、ループが繰り返す構造の要素のもの、A...
/a...
は、ループに渡される引数を表します。Iterator<T> iterator(A...); // defaults to Iterable::iterator V init(A...); V body(V,T,A...); V iteratedLoop(A... a...) { Iterator<T> it = iterator(a...); V v = init(a...); while (it.hasNext()) { T t = it.next(); v = body(v, t, a...); } return v; }
- APIのノート:
- 例:
このメソッドの実装は、およそ以下のように表現することができる:// get an iterator from a list static List<String> reverseStep(List<String> r, String e) { r.add(0, e); return r; } static List<String> newArrayList() { return new ArrayList<>(); } // assume MH_reverseStep and MH_newArrayList are handles to the above methods MethodHandle loop = MethodHandles.iteratedLoop(null, MH_newArrayList, MH_reverseStep); List<String> list = Arrays.asList("a", "b", "c", "d", "e"); List<String> reversedList = Arrays.asList("e", "d", "c", "b", "a"); assertEquals(reversedList, (List<String>) loop.invoke(list));
MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) { // assume MH_next, MH_hasNext, MH_startIter are handles to methods of Iterator/Iterable Class<?> returnType = body.type().returnType(); Class<?> ttype = body.type().parameterType(returnType == void.class ? 0 : 1); MethodHandle nextVal = MH_next.asType(MH_next.type().changeReturnType(ttype)); MethodHandle retv = null, step = body, startIter = iterator; if (returnType != void.class) { // the simple thing first: in (I V A...), drop the I to get V retv = dropArguments(identity(returnType), 0, Iterator.class); // body type signature (V T A...), internal loop types (I V A...) step = swapArguments(body, 0, 1); // swap V <-> T } if (startIter == null) startIter = MH_getIter; MethodHandle[] iterVar = { startIter, null, MH_hasNext, retv }, // it = iterator; while (it.hasNext()) bodyClause = { init, filterArguments(step, 0, nextVal) }; // v = body(v, t, a) return loop(iterVar, bodyClause); }
- パラメータ:
iterator
- ループを開始するイテレータを返すためのオプションのハンドル。 非null
の場合、ハンドルはIterator
またはサブ型を戻す必要があります。 他の制約については上記を参照してください。init
- ループ変数の初期値を提供するオプションの初期化子。 デフォルトの初期値を意味するnull
かもしれません。 他の制約については上記を参照してください。body
- ループの本文ですが、null
ではありません。 標準ケース(詳細は上記を参照)でループ・パラメータと結果型を制御します。 それは、それ自身の戻り値の型(非空白の場合)と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
、zero、またはfalse
の値がプレースホルダーとして提供されます。target
ハンドルにvoid
戻り型がある場合、2番目の引数は存在しません。 (引数の型変換を除いて、結合子は、対応する逆説的な引数を省略し、null
またはゼロ値を挿入するのではなく、パラメータ・リストのvoid
値を表します。)target
ハンドルとcleanup
ハンドルには、対応する引数と戻り値の型が同じでなければなりません。ただし、cleanup
ハンドルで後続の引数が省略される場合があります。 また、cleanup
ハンドルには、1つまたは2つの追加の先行パラメータが必要です:Throwable
は、target
は、target
ハンドル(もしあれば)によってスローされた例外を運びます。そしてtarget
とcleanup
の両方の戻り型と同じ型のパラメータで、target
ハンドルの実行結果を保持します。target
がvoid
を返した場合、このパラメータは存在しません。
結果のアダプタの擬似コードは、以下のようになります。 コードでは、
V
はtry/finally
構文の結果型を表します。A
/a
、クリーンアップによって消費される結果ハンドルに対する引数の型と値。B
/b
は、クリーンアップによって破棄された結果のハンドルへの引数のものです。V target(A..., B...); V cleanup(Throwable, V, A...); V adapter(A... a, B... b) { V result = (zero value for V); Throwable throwable = null; try { result = target(a..., b...); } catch (Throwable t) { throwable = t; throw t; } finally { result = cleanup(throwable, result, a...); } return result; }
保存された引数(擬似コード内の
a...
)は、ターゲットの実行によって変更できないので、呼び出された場合は、呼び出し側からクリーンアップにそのまま渡されます。クリーンアップが常にスローされたとしても、ターゲットとクリーンアップは同じ型を返す必要があります。 このようなスロー・クリーン・アップを作成するには、
throwException
を使用してクリーンアップ・ロジックを作成し、正しい戻り値型のメソッド・ハンドルを作成します。tryFinally
は例外を通常のリターンに変換しないことに注意してください。 まれに、例外をそのように変換する必要がある場合は、まずcatchException(MethodHandle, Class, MethodHandle)
でターゲットをラップして送信例外をキャプチャし、tryFinally
でラップします。cleanup
の最初のパラメータ・タイプは、専用サブタイプではなくThrowable
を宣言することをお薦めします。 これにより、target
がスローする例外を除き、常にcleanup
が起動されるようになります。 絞込みタイプを宣言すると、try-finally
によってスローされた例外のタイプがtarget
によってスローされた例外のタイプがcleanup
の最初のパラメータ・タイプに代入できない場合に、ClassCastException
がスローされる可能性があります。VirtualMachineError
、LinkageError
およびRuntimeException
の様々な例外タイプは、ほとんどすべての種類のJavaコードが原理内でスローされる可能性があることに注意してください。(例)のみを捕捉するfinally句は、IOException
3 codektj 4コードの外部キーをマスクします。- パラメータ:
target
- 実行がtry
ブロックにラップされるハンドル。cleanup
- finallyブロックで呼び出されたハンドル。- 戻り値:
- 2つの引数からなる
try-finally
ブロックを具現化するメソッド・ハンドル。 - 例外:
NullPointerException
- いずれかの引数がnullの場合IllegalArgumentException
-cleanup
が必要な先行引数を受け入れない場合、またはメソッドのハンドル型が戻り値の型および対応する末尾のパラメータで一致しない場合- 導入されたバージョン:
- 9
- 関連項目:
catchException(MethodHandle, Class, MethodHandle)
-