Javaのクロージャいじってみた(4)

6.関数参照(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);

 
 

コメント

このブログの人気の投稿

日食ツアーその後

NashornがOpenJDKのリポジトリに入ってたのでビルドしてみた

Javaのクロージャをいじってみた。(1)