Javaのクロージャいじってみた(4)
6.関数参照(Function Reference)
新しい記述が導入されるみたい。
クラス/インスタンスメンバへの参照は、"."演算子だが、
関数参照として新しく"#"演算子(みたいの)が導入されている。
このときは引数は型のみ記述している。メソッドを呼び出すというより、
クロージャとして取得したいメソッドのシグネチャを指定している感じ。
.netのデリゲート生成と似ている気がする。
例)
関数参照のコード
逆コンパイルしたコード
finalも@Sharedも無しでコンパイルできたのは自動でfinal代入コードが
挿入されるためと判明。
仕組みとしては上記の新ステートメントをみつけたら、指定のメソッドの
ラッパークラスを生成し、必要に応じてinvokeで実行する。
機能はjava.util.refrection.Methodをinvokeするような雰囲気だけど、
実装ではリフレクションは利用していない。
指定メソッドをラップするクラスを自動生成している。とても明快。
・個人的に注意点した方がいいと思ったこと
インスタンスメソッドの関数参照の場合、最新の参照を取得する必要があるため
クロージャオブジェクトはスタティックフィールドではなく、メソッドローカルで
毎回生成されるコードになる。(無名クラスと同じ状態)
その上、このnewはシンタックスシュガーで見えない。処理速度が重視される
システムではループ内の利用などは注意が必要なのではないかと思われます。
個人的にはFunction Referenceはあんま必要性が感じないなあ…。
↓手製で書けばいいんじゃないのかなあ…。これくらいは気にならないと思うのだけど。
これでは読みにくく、不必要に冗長的と判断されているのかな…。
新しい記述が導入されるみたい。
クラス/インスタンスメンバへの参照は、"."演算子だが、
関数参照として新しく"#"演算子(みたいの)が導入されている。
このときは引数は型のみ記述している。メソッドを呼び出すというより、
クロージャとして取得したいメソッドのシグネチャを指定している感じ。
.netのデリゲート生成と似ている気がする。
例)
関数参照のコード
String str = "Hello World !!";
{int,int=>String} subString = str#substring(int,int);
// 引数も"型"を指定する --> ~~~~~~
System.out.println("subString=" + subString.invoke(0, 5));
// 出力:subString=Hello
逆コンパイルしたコード
finalも@Sharedも無しでコンパイルできたのは自動でfinal代入コードが
挿入されるためと判明。
String s = "Hello World !!";
final String binding = s; // このコードが自動挿入され変数がクロージャに渡される
OII oii = new OII() {
public final String _2B_invoke(int i, int j) {
return binding.substring(i, j);
}
public final String invoke(int i, int j) {
return _2B_invoke(i, j);
}
public volatile Object invoke(int i, int j) throws Throwable {
return invoke(i, j);
}
final String val$binding;
{
binding = s;
super();
}
};
System.out.println((new StringBuilder()).append("[TEST] subString=")
.append((String)oii.invoke(0, 5)).toString());
仕組みとしては上記の新ステートメントをみつけたら、指定のメソッドの
ラッパークラスを生成し、必要に応じてinvokeで実行する。
機能はjava.util.refrection.Methodをinvokeするような雰囲気だけど、
実装ではリフレクションは利用していない。
指定メソッドをラップするクラスを自動生成している。とても明快。
・個人的に注意点した方がいいと思ったこと
インスタンスメソッドの関数参照の場合、最新の参照を取得する必要があるため
クロージャオブジェクトはスタティックフィールドではなく、メソッドローカルで
毎回生成されるコードになる。(無名クラスと同じ状態)
その上、このnewはシンタックスシュガーで見えない。処理速度が重視される
システムではループ内の利用などは注意が必要なのではないかと思われます。
個人的にはFunction Referenceはあんま必要性が感じないなあ…。
↓手製で書けばいいんじゃないのかなあ…。これくらいは気にならないと思うのだけど。
これでは読みにくく、不必要に冗長的と判断されているのかな…。
final String str = XXXX;
// ↓Function Reference
{int,int=>String} subStringA = str#substring(int,int);
// ↓手製
{int,int=>String} subStringB =
{String str =>
{int start, int length => str.substring(start,length)}
}.invoke(str);
コメント