2017-01-18 8 views
1

のクローニング、私の最初の試みでした:私は述語オブジェクトのクローンを作成したい述語

Predicate<String> p1 = str -> str.isEmpty(); 
Predicate<String> p2 = str -> p1.test(str); 

しかし、その場合には、あまりにもP1の変更、P2の変更場合。 p2が変わらないように述語をクローンする方法はありますか?

+3

ここでは何が複製されていますか?述語はステートレスなので、問題はないはずです。 – teppic

+0

古いものを再利用できないのはなぜですか? – Moira

+0

別の変数を導入してください。 touがp1を最終的にしてp3 = p1を導入した場合は、p1を変更不可として、p3を変更可能なrefとして使用できます。 –

答えて

2

あなたが直面している問題は、述語が変更されることではなく、述語によって暗黙的に参照される外部変数の1つが変更されることです。したがって、述語のコピーを作ることは、すでに不変なので、助けにならないでしょう。この問題を解決する必要がありp1の値をキャプチャするために一時変数を作る

:修正プログラムが動作します

Predicate<String> p1 = str -> str.isEmpty(); 
final Predicate<String> pTemp = p1; 
Predicate<String> p2 = str -> pTemp.test(str); 

理由は、あなたがたときにp1を再度割り当てることで、古い述語オブジェクトは変更されません。完全に新しい述語インスタンスに置き換えられます。古い述語オブジェクトはまだ存在しますが、ライブ参照がない場合は、ガベージコレクションの対象となります。

pTempを追加すると、古い述語は2つの変数、つまりp1pTempから参照されます。この時点で、p1を再割り当てすることはpTempには影響しないため、p2の動作も同様に変更されません。

これは、述語を段階的に構築するときに、ループ内でこれがより便利であると考えています。

+1

ありがとうございました、それはうまくいきますが、私は理由を理解していますが、シーンの後ろで何が起こっているのか説明できますか? – DBLouis

+0

クローン自体の役に立たないことに加えて、 'Predicate p2 = p1 :: test;'を使って 'p1'を新しい' Predicate'に永久にバインドすることができます。その後、 'p1'へのその後の変更は' p2'に影響を与えません。説明するために、なぜクローン化が役に立たないのか、単純に 'Predicate p2 = p1;'を使って同じことを達成できます。クローンはしませんが、同じ効果があります。 'p1'と' p2'で参照される述語は同じ動作とそれに続く 'p1'の変更は' p2'には何の効果もありません... – Holger