2012-10-17 12 views
12

Guavaでは、ImmutableListにアイテムを追加または削除する効率的な方法があります(もちろん、プロセスで新しいリストを作成する)。Guava ImmutableListへのアイテムの追加と削除

私が思い付くことができます最も簡単な方法はこれです:私がやって避けたい何

private ImmutableList<String> foos = ImmutableList.of(); 

public void addFoo(final String foo) { 
    if (this.foos.isEmpty()) { 
     foos = ImmutableList.of(foo); 
    } else { 
     foos = ImmutableList.<String>builder().addAll(foos).add(foo).build(); 
    } 
} 

public void removeFoo(final String foo) { 
    final int index = this.foos.indexOf(foo); 
    if (index > -1) { 
     final Builder<String> builder = ImmutableList.<String>builder(); 
     if (index > 0) builder.addAll(this.foos.subList(0, index)); 
     final int size = this.foos.size(); 
     if (index < size - 1) builder.addAll(this.foos.subList(index+1, size)); 
     this.foos = builder.build(); 
    } 
} 

はこれです:

public void removeFoo(final String foo) { 
    final ArrayList<String> tmpList = Lists.newArrayList(this.foos); 
    if(tmpList.remove(foo))this.foos=ImmutableList.copyOf(tmpList); 
} 

しかし残念ながら、それはそんなに単純で任意のGuava-より私が考えることができる唯一の方法。私は何かを逃したか?

+4

どのような上位レベルの問題を解決しようとしていますか?変更が必要な場合は、不変のリストを扱うべきではないかもしれません。 – sjr

+0

なぜそれを避けたいですか? –

+0

私は問題を簡単に解決することができますが、データ保持者の中で変更可能なリストに頼っているのですが、a)余分な中間コレクションを作成しなければならず、b)java.utilコレクションをguava ImmutableCollectionsとミックスする必要があります。 1つのパラダイムにそして、私は、コントロールを失うことなく、あるいは多くのCollections.unmodifiableListラッパーオブジェクトを作成することなく、 'getFoos()'メソッドでクライアントに渡したいので、ImmutableListを使いたいと思います。 –

答えて

7

ConcurrentModificationExceptionは、実際に並行性と同期には関係しません。変更可能なListに同時にアクセスすると、それが破損したり、例外がスローされたりする可能性があります(3つすべての可能性に備えてください)。あなたのコードは、この方法で失敗することはできませんが、マルチスレッドで、それはどちらか動作しません:同期なしとfoosvolatileをせずに

  • 、別のスレッドがこれまでにあなたが行った変更を確認するという保証はありません。
  • volatileであっても、2つのスレッドがfoosにアイテムを追加したときに、両方が元の値で始まり、次に最後に書き込まれたものが追加される(たとえば、そのアイテムのみが追加されるなど) )。

避けようとしているコードは避けてください。

  • を「私は余計な中間コレクションを作成する必要があります」 - はい、ない自由な昼食はありません。
    • は、リスト全体
    • を通じて追加の繰り返しを意味し、事前に結果のサイズを決定
    • または十分に大きなアレイを割り当て、結果のリスト
    • に必要な範囲をコピーしたり、十分な大きさの配列を割り当て、(時間を節約し、メモリを浪費する)、それの一部のみを使用
    • または不変のビューを作成する(時間とメモリの両方を節約するが、おそらく、後の時間を失うこと)
  • 私の知る限りフランクの答えは、述語が速い場合罰金である第一の可能性を、実装しています。
  • "私は1つのパラダイムに固執したいが、私は、java.utilコレクションとguava ImmutableCollectionsを混在させなければならない。" - はい、コレクションを変更するには、変更可能なコレクションが必要です。 ImmutableList.Builderは、最も一般的なケースだけをコンパクトに扱うことができます。

このような操作に最適化されたpersistent collectionsをご覧ください。しかし、あなたは期待してはいけません。永続リストはArrayListまたはImmutableListと同じくらい速くなります。

+0

OK、上記の例には同期が追加されていません。十分に複雑なので、同期を追加しませんでした。たとえば、例を使用する場合よりも同期を追加する方がはるかに簡単です。配列リスト。まだ:永続的なコレクションの提案は+1。多分、Guavaはそのような機能性を探す正しい場所ではありません。 –

+1

@SeanPatrickFloyd:Guavaチームは既存のものを複製することを拒否し、永続的なコレクションは[実際には適合しません]と言います(https://groups.google.com/d/msg/guava-discuss/G4E_Hg9GGv0/YFfQf3-AD3IJ )。 – maaartinus

+0

@maaartinus私は1つ[質問]を持っています(http://stackoverflow.com/questions/41925494/how-to-keep-retrying-block-machine-every-x-interval-until-url-is-executed-succes)グーバの再試行を使用していて、コードがスレッドセーフで、私がやっていることが正しいかどうかをチェックしたいと思っていましたか?あなたと確認するように考えられた答えはありません。 – john

13

あなたは中間ArrayListやビルダーを作成しない、フィルタリングにより削除し、一度だけリストを横断することができます

public void removeFoo(final String foo) { 
    foos = ImmutableList.copyOf(Collections2.filter(foos, 
      Predicates.not(Predicates.equalTo(foo))); 
} 

を追加するために、私はよりよい解決策が表示されません。

+0

私はこれを考えました(もちろん言及してくれないのは残念です)。問題は、すべてのオカレンスを削除しますが、List.remove()は最初のオカレンスだけを削除し、その機能を探していました。まだ:+1 –

+0

それからあなたの現在の実装のどちらかが得意だと思います(あなたが空になるので 'if(index> 0)'と 'if(index

関連する問題