public class MethodHandles extends Object
修飾子と型 | クラスと説明 |
---|---|
static class |
MethodHandles.Lookup
ルックアップ・オブジェクトは、メソッド・ハンドルの作成にアクセス・チェックが必要な場合のメソッド・ハンドル作成用ファクトリです。
|
修飾子と型 | メソッドと説明 |
---|---|
static MethodHandle |
arrayElementGetter(Class<?> arrayClass)
配列の各要素に対する読取りアクセスを提供するメソッド・ハンドルを生成します。
|
static MethodHandle |
arrayElementSetter(Class<?> arrayClass)
配列の各要素に対する書込みアクセスを提供するメソッド・ハンドルを生成します。
|
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 |
dropArguments(MethodHandle target, int pos, Class<?>... valueTypes)
いくつかのダミー引数を破棄してから指定された別のtargetメソッド・ハンドルを呼び出すメソッド・ハンドルを生成します。
|
static MethodHandle |
dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes)
いくつかのダミー引数を破棄してから指定された別のtargetメソッド・ハンドルを呼び出すメソッド・ハンドルを生成します。
|
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, 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 MethodHandles.Lookup |
lookup()
呼出し元のすべてのサポートされるバイトコード動作をエミュレートするためのフル機能を持つ
ルックアップ・オブジェクト を返します。 |
static MethodHandle |
permuteArguments(MethodHandle target, MethodType newType, int... reorder)
引数の順序を変更することによって、指定されたメソッド・ハンドルの呼出し順序を新しい型に適応させるメソッド・ハンドルを生成します。
|
static MethodHandles.Lookup |
publicLookup()
最小の信頼レベルを持つ
ルックアップ・オブジェクト を返します。 |
static <T extends Member> |
reflectAs(Class<T> expected, MethodHandle target)
直接メソッド・ハンドルの未チェックの解読を実行します。
|
static MethodHandle |
spreadInvoker(MethodType type, int leadingArgCount)
指定された
type の任意のメソッド・ハンドルを呼び出すメソッド・ハンドルを生成しますが、その際、指定された数の末尾の引数が単一の末尾のObject[] 配列で置き換えられます。 |
static MethodHandle |
throwException(Class<?> returnType, Class<? extends Throwable> exType)
指定された
exType の例外をスローするメソッド・ハンドルを生成します。 |
public static MethodHandles.Lookup lookup()
ルックアップ・オブジェクト
を返します。これらの機能には呼出し元へのprivateアクセスが含まれます。ルックアップ・オブジェクトのファクトリ・メソッドは、呼出し元がバイトコードを介してアクセスするメンバー(protectedおよびprivateのフィールドおよびメソッドを含む)の直接メソッド・ハンドルを作成できます。このルックアップ・オブジェクトは、信頼できるエージェントに委譲可能な1つの機能です。信頼できないコードからアクセス可能な場所に格納しないでください。
このメソッドは呼出し元依存です。つまり、呼出し元ごとに異なる値を返す可能性があります。
呼出し元クラスC
が指定された場合、この呼出しによって返されるルックアップ・オブジェクトは、同じ呼出し元クラスC
で実行するinvokedynamic命令のブートストラップ・メソッドに対してJVMによって提供されるルックアップ・オブジェクトと同等の機能を持ちます。
public static MethodHandles.Lookup publicLookup()
ルックアップ・オブジェクト
を返します。これは、publicのアクセス可能なフィールドやメソッドへのメソッド・ハンドルを作成する場合にのみ使用できます。
単に慣例により、このルックアップ・オブジェクトのルックアップ・クラスは、Object
になります。
ディスカッション: ルックアップ・クラスは、publicLookup().in(C.class)
形式の式を使用して、他の任意のクラスC
に変更できます。publicの名前に対するアクセスはどのクラスもすべて同じであるため、そのような変更によって新しいアクセス権が付与されることはありません。publicルックアップ・オブジェクトは常にセキュリティ・マネージャ・チェックが適用されます。また、呼出し元依存メソッドにアクセスすることもできません。
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
- メンバーが期待される型でない場合public static MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException
int
になります。arrayClass
- 配列の型NullPointerException
- 引数がnullの場合IllegalArgumentException
- arrayClassが配列型でない場合public static MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException
arrayClass
- 配列のクラスNullPointerException
- 引数がnullの場合IllegalArgumentException
- arrayClassが配列型でない場合public static MethodHandle spreadInvoker(MethodType type, int leadingArgCount)
type
の任意のメソッド・ハンドルを呼び出すメソッド・ハンドルを生成しますが、その際、指定された数の末尾の引数が単一の末尾のObject[]
配列で置き換えられます。結果となるインボーカは、次の引数を持つメソッド・ハンドルです。
MethodHandle
ターゲット
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()
(含む)までの範囲でない場合、または結果のメソッド・ハンドルの型のパラメータ数が多すぎる場合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
- 結果のメソッド・ハンドルの型のパラメータ数が多すぎる場合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
- 結果のメソッド・ハンドルの型のパラメータ数が多すぎる場合public static MethodHandle explicitCastArguments(MethodHandle target, MethodType newType)
元の型と新しい型が等しい場合はターゲットを返します。
MethodHandle.asType
の場合と同じ変換が許可されるほか、それらの変換が失敗した場合には、いくつかの追加の変換も適用されます。asType
で行われる変換の前に、あるいはその代わりに、次のいずれかの変換が可能であれば適用されます(T0、T1は型)。
(x & 1)!= 0
と同様に行われます。
target
- 引数の型を調整したあとに呼び出すメソッド・ハンドルnewType
- 新しいメソッド・ハンドルの期待される型NullPointerException
- どちらかの引数がnullの場合WrongMethodTypeException
- 変換できない場合MethodHandle.asType(java.lang.invoke.MethodType)
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つのパラメータの型が同一でない場合public static MethodHandle constant(Class<?> type, Object value)
メソッド・ハンドルが返される前に、渡された値が要求された型に変換されます。要求された型がプリミティブの場合はプリミティブ・ワイドニング変換が試みられ、それ以外の場合は参照変換が試みられます。
返されるメソッド・ハンドルはidentity(type).bindTo(value)
と同等です。
type
- 必要なメソッド・ハンドルの戻り値の型value
- 返す値NullPointerException
- type
引数がnullの場合ClassCastException
- 要求された戻り値の型に値を変換できない場合IllegalArgumentException
- 指定された型がvoid.class
の場合public static MethodHandle identity(Class<?> type)
type
- 必要なメソッド・ハンドルの唯一のパラメータと戻り値の型NullPointerException
- 引数がnullの場合IllegalArgumentException
- 指定された型がvoid.class
の場合public static MethodHandle insertArguments(MethodHandle target, int pos, Object... values)
新しいメソッド・ハンドルの型には、元のターゲットの型に含まれていたバインド・パラメータの型は含まれませんが、これは、新しいメソッド・ハンドルではもう、呼出し元がそれらの引数を指定する必要がないからです。
指定された引数のオブジェクトはそれぞれ、対応するバインド・パラメータの型に一致する必要があります。バインド・パラメータの型がプリミティブの場合、引数のオブジェクトはラッパーである必要があり、オブジェクトがアンボクシングされてプリミティブ値が生成されます。
pos
引数によってバインドするパラメータが選択されます。その範囲は0 - N-L (両端を含む)です。ここで、Nはターゲット・メソッド・ハンドルの引数長、Lは値配列の長さです。
target
- 引数を挿入したあとに呼び出すメソッド・ハンドルpos
- 引数の挿入位置(先頭の場合はゼロ)values
- 挿入する一連の引数NullPointerException
- ターゲットまたはvalues
配列がnullの場合MethodHandle.bindTo(java.lang.Object)
public static MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes)
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
- 引数を除去したあとに呼び出すメソッド・ハンドルvalueTypes
- 除去する引数の型pos
- 除去する最初の引数の位置(左端の場合は0)NullPointerException
- ターゲットがnullの場合、またはvalueTypes
リストまたはそのいずれかの要素がnullの場合IllegalArgumentException
- valueTypes
のいずれかの要素がvoid.class
の場合、またはpos
が負であるかターゲットの引数の数より大きい場合、または新しいメソッド・ハンドルの型に含まれるパラメータの数が多すぎる場合public static MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes)
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")); MethodHandle d0 = dropArguments(cat, 0, String.class); assertEquals("yz", (String) d0.invokeExact("x", "y", "z")); MethodHandle d1 = dropArguments(cat, 1, String.class); assertEquals("xz", (String) d1.invokeExact("x", "y", "z")); MethodHandle d2 = dropArguments(cat, 2, String.class); assertEquals("xy", (String) d2.invokeExact("x", "y", "z")); MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class); assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
このメソッドは次のコードとも同等です。
dropArguments
(target, pos, Arrays.asList(valueTypes))
target
- 引数を除去したあとに呼び出すメソッド・ハンドルvalueTypes
- 除去する引数の型pos
- 除去する最初の引数の位置(左端の場合は0)NullPointerException
- ターゲットがnullの場合、またはvalueTypes
配列またはそのいずれかの要素がnullの場合IllegalArgumentException
- valueTypes
のいずれかの要素がvoid.class
の場合、またはpos
が負またはターゲットの引数カウントより大きい場合、または新しいメソッド・ハンドルの型のパラメータ数が多すぎる場合public static MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters)
前処理は、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
結果となるアダプタの擬似コードを次に示します。
V 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..., f[i](v[i])..., b...); }
target
- 引数をフィルタリングしたあとで呼び出すメソッド・ハンドルpos
- フィルタリングする最初の引数の位置filters
- フィルタリング対象の引数に対して最初に呼び出すメソッド・ハンドルNullPointerException
- ターゲットがnullの場合またはfilters
配列がnullの場合IllegalArgumentException
- filters
の非null要素がターゲットの対応する引数型と一致しない場合(前述の説明を参照)、またはpos+filters.length
がtarget.type().parameterCount()
より大きい場合、または結果のメソッド・ハンドルの型のパラメータ数が多すぎる場合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(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...); void 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)
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
結果となるアダプタの擬似コードを次に示します。
V target(A...); T filter(V); T adapter(A... a) { V v = target(a...); return filter(v); } // and if the target has a void return: void target2(A...); T filter2(); T adapter2(A... a) { target2(a...); return filter2(); } // and if the filter has a void return: V target3(A...); void filter3(V); void adapter3(A... a) { V v = target3(a...); filter3(v); }
target
- 戻り値をフィルタリングする前に呼び出すメソッド・ハンドルfilter
- 戻り値に対して呼び出すメソッド・ハンドルNullPointerException
- どちらかの引数がnullの場合IllegalArgumentException
- 前述のようにfilter
の引数リストがターゲットの戻り値の型と一致しない場合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"));
結果となるアダプタの擬似コードを次に示します。
// 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
の引数の型と同一でない場合public static MethodHandle guardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback)
結果となるアダプタの擬似コードを次に示します。
テストの引数(擬似コードでは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
- テストに失敗した場合に呼び出すメソッド・ハンドルNullPointerException
- いずれかの引数がnullの場合IllegalArgumentException
- test
がbooleanを返さない場合、または(test
の戻り値の型を変更してターゲットの型と一致させても) 3つのすべてのメソッド型が一致しない場合public static MethodHandle catchException(MethodHandle target, Class<? extends Throwable> exType, MethodHandle handler)
ターゲットとハンドラの対応する引数と戻り値の型は基本的に同じである必要がありますが、ハンドラでは(guardWithTest
の述語と同様に)末尾の複数の引数を省略できます。さらにハンドラは、exType
またはスーパー・タイプの先頭のパラメータを追加で1つ持つ必要があります。
結果となるアダプタの擬似コードを次に示します。
保存された引数(擬似コードでは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
- 一致する例外がスローされた場合に呼び出すメソッド・ハンドルNullPointerException
- いずれかの引数がnullの場合IllegalArgumentException
- handler
が指定された例外の型を受け入れない場合、またはメソッド・ハンドルの型に含まれる戻り値の型と対応するパラメータが一致しない場合public static MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType)
exType
の例外をスローするメソッド・ハンドルを生成します。メソッド・ハンドルは、exType
の単一の引数を受け入れ、それを即時に例外としてスローします。メソッド型では形式上、returnType
の戻り値が指定されます。戻り値の型は、どのようなものでもかまいません。メソッド・ハンドルが通常どおりに戻ることは決してないので、メソッド・ハンドルの動作には何の影響もありません。returnType
- 期待するメソッド・ハンドルの戻り型exType
- 期待するメソッド・ハンドルのパラメータ型NullPointerException
- どちらかの引数がnullの場合 バグまたは機能を送信
詳細なAPIリファレンスおよび開発者ドキュメントについては、Java SEのドキュメントを参照してください。そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright© 1993, 2014, Oracle and/or its affiliates. All rights reserved.