2016-04-18 12 views
4

Java 8での作業に多少時間がかかりましたが、古いコードをリファクタリングしてストリーム操作を行うのが良いでしょう。古いコードは「機能する」が、私の目には本当に非効率的に見える。Java 8ストリーム:ストリーム・コレクション内の単一の項目を置き換えます。

私の質問の短いバージョンは、Listの1つの要素を見つけて、同じ要素の更新されたバージョンで置き換えようとしていることです(キーは同じですが、プロパティは毎回コードが呼び出されます)。

 try 
    { 
     List<Object> items = lookup(itemCache.getKey()); 
     for (int i = 0; i < items.size(); i++) 
     { 
      Object originalObject = items.get(i); 
      if (originalObject.getPropValue() == newObject.getPropValue()) 
      { 
       List<Object> newItems = new ArrayList<>(items); 
       newItems.set(i, newObject); 
       putIntoCache(newObject.getKey(), newItems); 
       break; 
      } 
     } 
    } 

    catch (Exception ex) { /*exception handling*/ } 

私は、これまでの流れについて読んだことに基づいて、私が私が確認したい要素を分離する.map()または.filter()を使用する必要があるようですが、それはまた、filterかのどちらか後に発生した操作のように思えますmapは、ストリームリスト内のすべての項目が.map()の影響を受けるリストまたはリストでは動作しません。

シンプルだと思われますが、私はその頭を包み込むのに苦労しています。最初のルックアップはListなので、私はストリームがこれをすべて置き換えることができると考えていました。 ArrayList<>()は元のコードに表示されますが、そのアイテムをそのキーで置き換えることができる限り、アイテムの順序は重要ではありません。

お手数をおかけしますようお願い申し上げます。

+2

ストリームはソースデータの_mutations_には適切ではありません。 – Savior

+0

トピックはありませんが、キャッシュが 'Map'を実装している場合、' List'を読んでキャッシュに書き戻すのではなく、 'Map.computeIfPresent(UnaryOperator )'を調べるかもしれません。 'computeIfAbsent'はConcurrentHashMapのスレッドセーフです。これらの答えで取られたread-modify-writeアプローチとは異なります。 –

答えて

11

あなたは、単に行うことができます。

List<Object> newItems = items.stream() 
    .map(o -> { 
     if(o.getPropValue() == newObject.getPropValue()) { 
      return newObject; 
     } else { 
      return o; 
     } 
    }).collect(toList()); 
putIntoCache(newObject.getKey(), newItems); 
+0

これは私が探していたものです。迅速な返信ありがとうございます。 – Patrick

+3

意味の違いに注意してください。元のコードはたかだか1つのオカレンスに置き換えられ、一致するものが見つからなければ何もしません。このコードはすべてのオカレンスを置き換え、常に新しいリストを作成して公開します。それ以外に、 'items.stream()。map(o-> o.getPropValue()== newObject.getPropValue()?newObject:o).collect(toList())' – Holger

+1

契約すれば簡略化することができます。 'newItems'はキャッシュ内のデータの可変コピーであるため、' Stream'の代わりに 'newItems.replaceAll()'を使うことができます。 –

2

適用したい機能は「小道具値と一致最初要素を置き換え」です。 最初の部分(およびbreak文)は、それ以前に処理されたすべてのエントリに依存するため、自明ではありません。言い換えれば、あなたの関数はいくつかの追加の状態に依存していることを意味するので、ドメインはboolean * Stringと表現できます。ここでbooleanは置換が行われたかどうかを示します。あなたは醜くなるのを見ることができます。

すべての値が一致する場合は、Jean Logeartの回答は大丈夫です。

+0

これは役に立ちます、ありがとうございます。 – Patrick

2

ストリームは実際にはこのコードスニペットにはあまり適していません。これは初期のbreakを持ち、同時にインデックスと要素の両方で動作するためです。

List<Object> items = lookup(itemCache.getKey()); 
IntStream.range(0, items.size()) 
    .filter(i -> items.get(i).getPropValue() == newItem.getPropValue()) 
    .findFirst() 
    .ifPresent(i -> { 
     List<Object> newItems = new ArrayList<>(items); 
     newItems.set(i, newObject); 
     putIntoCache(newObject.getKey(), newItems); 
    }); 

が本当に優れていることです:

あなたは、このような同等のステートメントを構築することができますか?私の意見では、特にそうではありません。ストリームの機能を実際に使用しているわけではなく、コントロールフロー構文をAPIに置き換えるだけです。

正確な動作があまり重要でない場合は、Jeanの回答のように、より良い例があります。

関連する問題