2016-07-29 2 views
1

ラムダを捕獲するには、オブジェクトが割り当てられている必要があります(Object[]またはabc$Lambda$xyzタイプ)。このプロセスを任意にカスタマイズすることは可能ですか?のは、私はこのコードを持っているとしましょう:プール捕獲ラムダ

private void test() { 
    int x = 5; 
    Supplier<Integer> supplier =() -> x; 
    foo(supplier); // potentially passes the supplier to another thread etc. 
} 

を、私はちょうどプールからそれを取得し、値を記入xをキャプチャするオブジェクトを割り当てたいが、代わりにしないでください。私はまた、ある時点でオブジェクトをプールに戻すことができることも知っています。

私は

Supplier<Integer> supplier = pool.get(x, v -> v); 

を書くことができそしてObject...を使用して割り当てを行うだろうと私は((異なる引数の型に特化したバージョンを持っている可能性がOK、割り当てはエスケープ解析によって排除されるという可能性があります... )しかし、それはかなり読めないコードをレンダリングするでしょう。したがって、私はより多くの側面のような方法を探しています。

はそのようなことは可能ですか?


EDIT:プールの機能をより明確にする、get

class IntHolderSupplier implements Supplier<Integer> { 
    int value; 
    IntFunction<Integer> func; 
    @Override public Integer get() { 
     return func.apply(value); 
    }   
} 

class Pool { 
    Supplier<Integer> get(int arg, IntFunction<Integer> func) { 
     IntHolderSupplier holder = ...; 
     holder.value = arg; 
     holder.func = func; 
     return holder; 
    } 
} 

として実装することができ、私が使用するすべての可能なタイプのラムダのために特定の署名と、このようなホルダーが必要になります。

私は関数を提供することで少し複雑になっているかもしれませんが、Supplier.get()の呼び出し時にキャプチャされた引数に追加の計算が適用される可能性があります。

そして、intがボックス化されて割り当てを生成できるという事実は無視してください。

+0

あなたは 'supplier =() - > pool.getInteger();'のようなものを意味しますか? – bradimus

+0

@bradimus申し訳ありませんが、私はその質問を理解していません。その意図は、ビジネスロジックが5を返すプールされたオブジェクトを取得することです。プールはこのビジネスロジックを知ることができません。 –

+0

このホルダーの実装は、Functionもキャプチャしていない場合にオブジェクトの作成を防ぐのに役立ちます。私はあなたがこの部分を最適化しなければならないところに非常に興味があります、あなたはそれが使用されることになる文脈を教えてください? –

答えて

1

プール捕捉ラムダ」は、誤った名称である。ラムダ式は、機能的インタフェースのインスタンスを得るための技術的解決策です。ラムダ式をプールするのではなくインタフェースインスタンスをプールするので、ラムダ式の技術的な面、つまり不変性やJRE/JVMが寿命を制御するという点を除いて、「プール機能インターフェイスインスタンス」と名前を付ける必要があります。

したがって、どのような種類のオブジェクトにもプールを実装できるように、これらのインスタンスのプールを実装できます。そのようなプールがラムダ式用に作成されたJVM管理対象オブジェクトよりも優れているとは思えませんが、試してみてください。

これは単純なので、不変のままにしておくと、別の値で再利用しようとしないでください。以前に取得した値に再び遭遇した場合にのみ再試行してください。

class SupplierCache { 
    static final int SIZE = 100; 
    static LinkedHashMap<Object,Supplier<Object>> CACHE = 
     new LinkedHashMap<Object, Supplier<Object>>(SIZE, 1f, true) { 
     @Override 
     protected boolean removeEldestEntry(Map.Entry<Object, Supplier<Object>> eldest) { 
      return size() > SIZE; 
     } 
    }; 
    @SuppressWarnings("unchecked") 
    static <T> Supplier<T> getSupplier(T t) { 
     return (Supplier<T>)CACHE.computeIfAbsent(t, key ->() -> key); 
    } 
} 

(あなたがそれを必要とする場合、スレッドの安全性を追加):ここでは、最後の100の遭遇した値のためのサプライヤーを保持Supplierキャッシュの一例です。したがって、Supplier<Integer> supplier =() -> x;Supplier<Integer> supplier = SupplierCache.getSupplier(x);に置き換えると、キャッシュ機能が得られます。また、キャッシュ機能をリリースする必要がないため、そのライフサイクルについてエラーが発生しやすいという前提はありません。

Supplierを実装するオブジェクトのプールを作成し、手動でインスタンスを再利用できるように変更可能なフィールドの値を返すことは、普通のクラスを作成するだけではあまり難しくありませんが、まだ使用されているオブジェクトを再利用するリスクを含む、手動メモリ管理によるワームの使用。これらのオブジェクトは、上記の例のように不変オブジェクトのように共有することはできません。また、オブジェクトの割り当てを、再利用可能なプーリングされたインスタンスと、使用後にインスタンスを明示的に戻すアクションを見つけるアクションに置き換えます。これがより高速になる理由はありません。

+0

'() - > x'を' SupplierCache.getSupplier(x) 'に置き換えるのは、私が避けたかったのです。 –

+0

もし、ラムダ式のソースコード形式を保持したいのであれば、疑わしい結果のため、説明されているように組み込みのソリューションはありません。ただし、コンパイルされたクラスファイルの上に実装することは可能です。一般に、JREは担当しているので、JREを変更せずに別の動作を注入したい場合は、バイトコード操作/インストルメンテーションを使用して、ブートストラップメソッドをそのキャッシング機能を持つ別の実装にリダイレクトする必要があります。 – Holger

+0

@Holger LRUキャッシュについての素敵なトリックです。間違いなく1つプラス! – Eugene

関連する問題