为了平等,我经常必须与某种类型的实例进行比较,但我不需要比较所有内容,而只需要比较某些字段。我通常是这样的:
Comparator<SomeType> c = Comparator.comparing(SomeType::getNumber)
.thenComparing(SomeType::getType)
.thenComparing(SomeType::getSite)
.thenComparing(SomeType::getAddition)
.thenComparing(SomeType::getImportantFlag);
if (c.compare(old, new) == 0) {
...
}
由于我经常不得不这样做,我想知道是否有通用的方法可以做到这一点。
我必须比较的所有对象都扩展了某个基类。有没有办法写一个静态方法为我做所有这些比较?我在考虑一个静态方法,该方法必须具有要比较的对象的参数和所有方法引用的vararg参数:
public static <T extends BaseType> boolean areFieldsEqual(T left, T right, whatShouldIPutHere... fields) {
}
但是我不知道如何传递方法引用以及如何在方法内的比较器中使用它们。可以以某种方式完成此操作,还是应该尝试其他方法?
答案 0 :(得分:3)
我设法提出了一些可行的方法:
public static <T extends BaseType> boolean areFieldsEqual(T left, T right, Function<T,? extends Comparable>... fields)
{
if (fields.length < 1) {
return true;
}
Comparator<T> c = Comparator.comparing(fields[0]);
for (int i = 1; i < fields.length; i++) {
c = c.thenComparing (fields[i]);
}
return c.compare(left, right) == 0;
}
测试类:
class BaseType {
String x;
int y;
public BaseType (String x, int y) {
this.x=x;
this.y=y;
}
String getX () {return x;}
int getY () { return y;}
}
class SubType extends BaseType {
String z;
public SubType (String x, int y,String z) {
super(x,y);
this.z=z;
}
String getZ () {return z;}
}
用法:
BaseType one = new BaseType("some",1);
BaseType two = new BaseType("some",2);
SubType three = new SubType("some",1,"else");
SubType four = new SubType("some",2,"else");
System.out.println (areFieldsEqual(one,two,BaseType::getX,BaseType::getY));
System.out.println (areFieldsEqual(three,four,SubType::getZ,BaseType::getX));
输出:
false
true
答案 1 :(得分:2)
将varargs
与泛型一起使用将导致类似Potential heap pollution via varargs parameter
的编译器警告。通常,为避免此类情况,我们可以提供以下几种功能:
具有单个字段:
public static <T extends BaseType> boolean areFieldsEqual(
T first, T second, Function<? super T, ? extends Comparable> keyExtractor) {
Comparator<T> comp = Comparator.comparing(keyExtractor);
return comp.compare(first, second) == 0;
}
具有两个字段:
public static <T extends BaseType> boolean areFieldsEqual(
T first, T second, Function<T, ? extends Comparable> firstField,
Function<T, ? extends Comparable> secondField) {
Comparator<T> comp = Comparator.comparing(firstField).thenComparing(secondField);
return comp.compare(first, second) == 0;
}
使用varargs
。由于我们没有存储fields
中的任何内容,因此可以在此方法上使用@SafeVarargs
:
@SafeVarargs
public static <T extends BaseType> boolean areFieldsEqual(
T first, T second, Function<T, ? extends Comparable>... fields) {
if (fields.length < 1) {
return true;
}
Comparator<T> comp = Comparator.comparing(fields[0]);
for (int i = 1; i < fields.length; i++) {
comp = comp.thenComparing(fields[i]);
}
return comp.compare(first, second) == 0;
}
答案 2 :(得分:1)
这是您可以使用的基本概念:
List<Function<SomeType, Comparable>> fieldsToTest = new ArrayList<>();
fieldsToTest.add(SomeType::getType);
fieldsToTest.add(SomeType::getSite);
System.out.println(areFieldsEqual(new SomeType(...), new SomeType(...), fieldsToTest));
areFieldsEqual
方法实现:
static <T extends BaseType> boolean areFieldsEqual(T left, T right,
List<Function<T, Comparable>> fields) {
Comparator<T> c = fields.stream().reduce(
(l, r) -> 0, Comparator::thenComparing, Comparator::thenComparing);
return c.compare(left, right) == 0;
}
或者,如果您想使用varargs
参数:
static <T extends BaseType> boolean areFieldsEqual(T left, T right,
Function<T, Comparable>... fields) {
Comparator<T> c = Arrays.stream(fields).reduce(
(l, r) -> 0, Comparator::thenComparing, Comparator::thenComparing);
return c.compare(left, right) == 0;
}