Java:如何使用不同的 equals 定义执行列表操作?
Java:如何使用不同的 equals 定义执行列表操作?
我有两个通用 POJO 列表。我需要根据比较列表中 POJO 的不同方式对列表执行一些集合操作。
例如,如果我的 POJO 具有以下结构:(
public class GenericPojo {
private String id;
private String address;
private String city;
private String country;
private String extraDetails;
}
具有适当的 getter 和 setter)
给定 List1
和 List2
,我将如何找到:
List1 - List2(如果只是 ID 相等,则 GenericPojo
类相等)
List1 和 List2 的交集(其中 id
、address
、city
、country
,但 GenericPojo
的 extraDetails
不相等)
两个不同的自定义比较器类在这里会有帮助吗?是否有任何库可以有效地处理这些操作,或者我应该尝试实现自己的库?
Java: How do I perform list operations with different definitions of equals?
I have two lists of generic POJOs. I need to perform some set operations on the lists based on different ways of comparing the POJOs within the lists.
For example, if my POJO had the following structure:
public class GenericPojo {
private String id;
private String address;
private String city;
private String country;
private String extraDetails;
}
(with the appropriate getters and setters)
Given List1<GenericPojo>
and List2<GenericPojo>
, how would I find:
List1 - List2 (where the GenericPojo
classes are equal if just the IDs are equal)
Intersect of List1 and List2 (where id
, address
, city
, country
, but not extraDetails
of GenericPojo
are equal)
Would two different custom comparator classes be helpful here? Are there any libraries that handle these operations effectively or should I try implementing my own?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
如果您必须操纵超出您控制范围的类,我建议使用委托。这是我的尝试:
EqualityChecker
接口。EqualityChecker
具体实例,它将为您执行相等测试。因此,您可以将这两个操作添加到您已为其编写
EqualityChecker
的任何类型对象的所有现有List
中。进一步改进:您还可以编写一个默认
EqualityChecker
,它只调用比较对象的 equals 方法。然后,您可以重载这两个新操作以默认EqualityChecker
。If you must manipulate class out of your control, I would suggest using delegation. Here is my try:
RichList<T>
wrapper aroundList
s implementing theList
contract, based on the decorator pattern.EqualityChecker<T>
inteface, with a single method `public boolean equal( T t1, T, t2).EqualityChecker<T>
concrete instance that will do the equality test for you.So you can add both operations to all existing
List
s for any kind of object for which you have written anEqualityChecker
.Further improvements: You can also write a default
EqualityChecker<T>
which just calls the equals method of the compared objects. You can then overload both new operations to default theEqualityChecker
.如果您的列表不包含重复项(相对于假设的自定义比较器类),您可以使用两个 TreeSet,分别用两个比较器实例化。
这样做的一个缺点(除了重复约束之外)是迭代元素时获得的顺序取决于比较器。
If your lists contain no duplicates (with repsect to the hypothetical custom comparator classes) you can use two TreeSets instead, instantiated with your two comparators respectively.
A drawback of this (apart from the duplication constraint) is that the order you get when iterating over elements depend on the comparators.
鉴于您对平等的具体要求,
List#removeAll()
和List#retainAll()
不符合您的需求,所以我认为您需要一个自定义实现来执行与这两个操作类似的操作。Given your specific requirements on equality,
List#removeAll()
andList#retainAll()
won't fit your needs so I think you'll need a custom implementation to do something similar to both operations.没有遵循 List 契约的解决方案,并且现有的 list 实现都不允许您提供比较器。 List 合约根据每个元素的 equals(Object) 方法定义列表的行为。
如果比较器的
compare
方法与每个元素的equals(Object)
方法不一致,那么使用具有不同比较器的 TreeSet 的建议也违反了约定。在实践中,您可能需要实现自己的列表类。您可以将其设为不严格遵循 List 约定的 List 实现,但您需要小心,这不会破坏其他库方法/类。
There is no solution that obeys the List contract, and none of the existing implementations of list allow you to supply a comparator. The List contract defines the behavior of the list in terms of each element's
equals(Object)
method.The suggestion of using TreeSets with different comparators is also a violation of the contract if the comparator's
compare
method is inconsistent with each element'sequals(Object)
method.In practice you may need to implement your own list classes. You could make it a List implementation that doesn't strictly follow the List contract, but you need to be careful that this doesn't break other library methods / classes.
如果您不想自己编写集合操作并且您不介意浪费一些 CPU 和内存资源,您可以:
WrappedPojo
构造>GenericPojoWrappedPojo
提供了equals()
的合适实现,WrappedPojo
的新列表来执行操作 操作完成后,将丑陋但简单。
If you don't want to program the set operations yourself and you don't mind wasting some CPU and memory resources, you could:
WrappedPojo
s based on yourGenericPojo
sWrappedPojo
suitable implementations ofequals()
WrappedPojo
to do the operation onGenericPojo
s back to their original containers (if needed) after the operation's finished.Ugly but simple.
您可以通过以下方法将所有这些保留在域对象中:
在
GenericPojo
上实现equals(
...)
>id。的
字段。equals(
...)
将WrappedPojo
定义为GenericPojo
的包装器GenericPojo我认为根本问题是试图拥有一个具有不同平等定义的单一域类。
You could keep all of this in the domain objects by the following approach:
equals(
...)
onGenericPojo
based only onid
.WrappedPojo
as a wrapper aroundGenericPojo
with anequals(
...)
based on the additionalGenericPojo
fields.I suggest that the root issue is trying to have a single domain class with different definitions of equality.
您尝试执行的两个操作都是函数式的,尽管 Java 不能很好地支持这些操作,并且您可能会以非常不同的方式编写它们。
您可能必须重新考虑您想要实现的目标以适合 java。
您正在做的是对数据类型的投影(即字段的子集)执行操作。
您使用的操作也是 Set 操作,而不是 List 操作。例如,您不能获取两个列表的交集(或者至少您必须定义这意味着什么),“删除”可能也不会完全按照您对列表的预期执行。
想象一下,您有一个方法,它返回仅包含您指定的字段的 pojo 集合。我过去写过一个库,可以通过动态生成的类来有效地完成此操作,请查看函数式 Java 或类似的库。
Both operations you are trying to perform are functional, though Java doesn't support these very well and you are likely to be writing them in a very different way.
You may have to rethink what it is you are trying to achieve to suit java.
What you are doing is performing an operation on a projection of the data type (i.e. for a sub set of fields)
The operations you are using are also Set operations, rather than List operations. e.g. you cannot take an intersection of two lists (or at least you have to define what that means) Remove may not perform exactly as you expect for list as well.
Imagine you have a method which returns a collection of pojos with just the fields you specify. I have written a library to do this efficiently with dynamicly generated class in the past, have a look at functional Java or similar.