7

Java: equals の定義が異なるリスト操作を実行するにはどうすればよいですか?

一般的な POJO の 2 つのリストがあります。リスト内の POJO を比較するさまざまな方法に基づいて、リストに対していくつかの集合操作を実行する必要があります。

たとえば、POJO に次の構造があるとします。

public class GenericPojo {
    private String id;
    private String address;
    private String city;
    private String country;
    private String extraDetails;
}

(適切なゲッターとセッターを使用)

List1<GenericPojo>とが与えられた場合List2<GenericPojo>、どのように見つけますか:

List1 - List2 ( GenericPojoID だけが等しい場合、クラスは等しい)

List1 と List2 の交差 (ここidで、addresscity、、が等しくcountryない)extraDetailsGenericPojo

ここで、2 つの異なるカスタム コンパレータ クラスが役に立ちますか? これらの操作を効果的に処理するライブラリはありますか、それとも独自に実装してみる必要がありますか?

4

7 に答える 7

2

クラスを制御できないように操作する必要がある場合は、委任を使用することをお勧めします。これが私の試みです:

  1. デコレータ patternに基づいて、コントラクトを実装する s のRichList<T>ラッパーを作成します。ListList
  2. EqualityChecker<T>単一のメソッド `public boolean equal( T t1, T, t2) でインターフェイスを作成します。
  3. 汎用 pojo にこのインターフェースを 2 回実装します。1 つは ID のみをチェックし、もう 1 つは他のフィールドをチェックします。
  4. 関心のある両方のメソッド (減算の設定と交差の設定) を追加しますがEqualityChecker<T>、等価テストを実行する具体的なインスタンスである補足引数を使用します。

したがってListEqualityChecker.

さらなる改善:比較されたオブジェクトの equals メソッドを呼び出すだけのデフォルト を作成することもできます。EqualityChecker<T>次に、両方の新しい操作をオーバーロードして、EqualityChecker.

于 2009-12-06T14:06:42.760 に答える
1

平等に関する特定の要件を考えるList#removeAll()List#retainAll()、ニーズに合わないため、両方の操作と同様のことを行うには、カスタム実装が必要になると思います。

于 2009-12-06T13:20:50.933 に答える
1

リストに重複が含まれていない場合 (架空のカスタム コンパレーター クラスに関連して)、2 つのコンパレーターでそれぞれインスタンス化された 2 つの TreeSet を代わりに使用できます。

これの欠点 (重複制約は別として) は、要素を反復処理するときに得られる順序がコンパレーターに依存することです。

于 2009-12-06T12:57:59.653 に答える
0

Listコントラクトに従うソリューションはなく、listの既存の実装では、コンパレータを提供できません。リストコントラクトは、各要素のequals(Object)メソッドの観点からリストの動作を定義します。

compareコンパレータのメソッドが各要素のメソッドと矛盾している場合、異なるコンパレータでTreeSetを使用するという提案も契約違反になりequals(Object)ます。

実際には、独自のリストクラスを実装する必要がある場合があります。Listコントラクトに厳密に従わないList実装にすることもできますが、他のライブラリメソッド/クラスを壊さないように注意する必要があります。

于 2009-12-06T13:21:24.150 に答える
0

セット操作を自分プログラムしたくなく、CPU とメモリ リソースをいくらか浪費してもかまわない場合は、次のことができます。

  • あなたのWrappedPojoに基づいて を構築しますGenericPojo
  • WrappedPojoの適切な実装を与えるequals()
  • WrappedPojo操作を行う適切な種類の新しいリストを作成する
  • 操作の終了後、含まれている を元のコンテナーにコピーしますGenericPojo(必要な場合)。

醜いがシンプル。

于 2009-12-06T13:30:27.403 に答える
0

次のアプローチにより、これらすべてをドメイン オブジェクトに保持できます。

  1. のみに基づいてequals(...)を実装します。GenericPojoid
  2. 追加フィールドに基づいて...を使用しWrappedPojoてラッパーとして定義します。GenericPojoequals()GenericPojo
  3. 2 番目のユース ケースでは、ラップされたインスタンスのリストを使用します。

根本的な問題は、単一のドメイン クラスにさまざまな等価の定義を持たせようとしていることにあると思います。

于 2009-12-06T13:34:43.553 に答える
0

実行しようとしている操作は両方とも機能しますが、Java はこれらを十分にサポートしておらず、非常に異なる方法で記述している可能性があります。Java に適合させるために何を達成しようとしているのかを再考する必要があるかもしれません。

あなたがしているのは、データ型の射影に対して操作を実行することです(つまり、フィールドのサブセットに対して)

使用している操作も、List 操作ではなく Set 操作です。たとえば、2 つのリストの共通部分を取得することはできません (または、少なくともその意味を定義する必要があります)。Remove は、リストに対して期待どおりに動作しない場合があります。

指定したフィールドだけで pojo のコレクションを返すメソッドがあるとします。過去に動的に生成されたクラスでこれを効率的に行うためのライブラリを作成しました。機能的なJavaなどを見てください。

public static <Pojo, Pojo2> Set<Pojo2> project(Collection<Pojo> collection,
      String... fieldsToRetain);

List1 - List2 (ID だけが等しい場合、GenericPojo クラスは等しい)

Set<PojoWithId> setOfIds = project(list1, "id")
setOfIds.retainAll(project(list2, "id"));

List1 と List2 の交差 (id、address、city、country、ただし GenericPojo の extraDetails は等しくない)

Set<PojoWithThreeFields> intersection = project(list1, "id", "address", "city", "country");
intersection.retainAll(project(list2, "id", "address", "city", "country"));
于 2009-12-06T15:24:24.060 に答える