Java 如何缩短多字段比较器?
我正试图用java8编写一个比较器,它依赖于使用lambda的两个标准。我有一份名单。一个人有以下方法:Java 如何缩短多字段比较器?,java,reflection,lambda,comparator,Java,Reflection,Lambda,Comparator,我正试图用java8编写一个比较器,它依赖于使用lambda的两个标准。我有一份名单。一个人有以下方法: Person{ String getFirstName(); String getLastName(); int getHeight(); Date getBirthday(); } 列表的排序取决于两个可由will选择的标准。所以这个列表应该按照名字和生日,或者名字和身高等等来排序 我的方法是创建一个switch-case块,在其中我查看标准的不同组合。但这一方法
Person{
String getFirstName();
String getLastName();
int getHeight();
Date getBirthday();
}
列表的排序取决于两个可由will选择的标准。所以这个列表应该按照名字和生日,或者名字和身高等等来排序
我的方法是创建一个switch-case块,在其中我查看标准的不同组合。但这一方法变得太大了
switch (holder.criteria1) {
case FIRSTNAME:
switch (holder.criteria2) {
case FIRSTNAME:
list.sort(Comparator.comparing(Person::getFirstName,
Comparator.nullsFirst(String::compareTo)));
break;
case LASTNAME:
list.sort(Comparator.comparing(Person::getFirstname,
Comparator.nullsFirst(String::compareTo)).thenComparing(
Person::getLastName, Comparator.nullsFirst(String::compareTo)));
break;
case HEIGHT:
list.sort(Comparator.comparing(Person::getFirstname,
Comparator.nullsFirst(String::compareTo)).thenComparing(
Person::getHeight, Comparator.nullsFirst(Integer::compareTo)));
break;
case BIRTHDAY:
list.sort(Comparator.comparing(Person::getFirstname,
Comparator.nullsFirst(String::compareTo)).thenComparing(
Person::getBirthday, Comparator.nullsFirst(Date::compareTo)));
break;
}
break;
我必须对每个案例组合重复这一点。标准2中四分之三的情况几乎相同,只是方法名和类型发生了变化。这是一个非常丑陋和长的代码,我想以更好的方式重新设计它
有没有一种方法可以通过使用反射来缩短这个时间?也许你可以这样做:
public enum Holder{
FIRSTNAME{
@override
Function getFunction(){
return Person::getFirstName;
}
}
........
abstract Function getFunction();
}
那么你只需要这个电话:
list.sort(Comparator.comparing(holder1.getFunction(),
Comparator.nullsFirst(String::compareTo)).thenComparing(
holder2.getFunction(), Comparator.nullsFirst(String::compareTo)));
也许你可以这样做:
public enum Holder{
FIRSTNAME{
@override
Function getFunction(){
return Person::getFirstName;
}
}
........
abstract Function getFunction();
}
那么你只需要这个电话:
list.sort(Comparator.comparing(holder1.getFunction(),
Comparator.nullsFirst(String::compareTo)).thenComparing(
holder2.getFunction(), Comparator.nullsFirst(String::compareTo)));
您可以将比较器存储在枚举值中,然后按需组合:
enum SortOn {
FIRSTNAME(Comparator.comparing(Person::getFirstName,
Comparator.nullsFirst(String::compareTo))),
LASTNAME(Comparator.comparing(Person::getLastName,
Comparator.nullsFirst(String::compareTo))),
HEIGHT(Comparator.comparing(Person::getHeight,
Comparator.nullsFirst(Integer::compareTo))),
BIRTHDAY(Comparator.comparing(Person::getBirthday,
Comparator.nullsFirst(Date::compareTo)));
public final Comparator<Person> comparator;
private SortOn(Comparator<Person> comparator) {
this.comparator = comparator;
}
}
...
public void sort(SortOn criteria1, SortOn criteria2) {
if(criteria1 == criteria2) {
list.sort(criteria1.comparator);
} else {
list.sort(criteria1.comparator.thenComparing(criteria2.comparator));
}
}
您可以将比较器存储在枚举值中,然后按需组合:
enum SortOn {
FIRSTNAME(Comparator.comparing(Person::getFirstName,
Comparator.nullsFirst(String::compareTo))),
LASTNAME(Comparator.comparing(Person::getLastName,
Comparator.nullsFirst(String::compareTo))),
HEIGHT(Comparator.comparing(Person::getHeight,
Comparator.nullsFirst(Integer::compareTo))),
BIRTHDAY(Comparator.comparing(Person::getBirthday,
Comparator.nullsFirst(Date::compareTo)));
public final Comparator<Person> comparator;
private SortOn(Comparator<Person> comparator) {
this.comparator = comparator;
}
}
...
public void sort(SortOn criteria1, SortOn criteria2) {
if(criteria1 == criteria2) {
list.sort(criteria1.comparator);
} else {
list.sort(criteria1.comparator.thenComparing(criteria2.comparator));
}
}
作为附录,此处的衍生变体避免了代码重复:
enum SortOn {
FIRSTNAME(Person::getFirstName),
LASTNAME(Person::getLastName),
HEIGHT(Person::getHeight),
BIRTHDAY(Person::getBirthday);
public final Comparator<Person> comparator;
private <U extends Comparable<U>> SortOn(Function<Person,U> f) {
this.comparator = Comparator.comparing(f,
Comparator.nullsFirst(Comparator.naturalOrder()));
}
private SortOn(ToIntFunction<Person> f) {
this.comparator = Comparator.comparingInt(f);
}
}
或支持任意数量的标准:
public static void sort(List<Person> list, SortOn... criteria) {
list.sort(Arrays.stream(criteria).map(c -> c.comparator)
.reduce(Comparator::thenComparing)
.orElseThrow(() -> new IllegalArgumentException("no criteria given")));
}
作为附录,此处的衍生变体避免了代码重复:
enum SortOn {
FIRSTNAME(Person::getFirstName),
LASTNAME(Person::getLastName),
HEIGHT(Person::getHeight),
BIRTHDAY(Person::getBirthday);
public final Comparator<Person> comparator;
private <U extends Comparable<U>> SortOn(Function<Person,U> f) {
this.comparator = Comparator.comparing(f,
Comparator.nullsFirst(Comparator.naturalOrder()));
}
private SortOn(ToIntFunction<Person> f) {
this.comparator = Comparator.comparingInt(f);
}
}
或支持任意数量的标准:
public static void sort(List<Person> list, SortOn... criteria) {
list.sort(Arrays.stream(criteria).map(c -> c.comparator)
.reduce(Comparator::thenComparing)
.orElseThrow(() -> new IllegalArgumentException("no criteria given")));
}
请不要仅仅为了缩短代码而引入反射。为每个标准创建一个比较器,并根据所选选项提供正确的比较器。第二个开关不应该是打开holder.criteria2或其他什么吗?这是一个很好的示例,说明了“告诉-不要问”原则。您不需要查询条件,然后决定如何排序;相反,您应该更改代码,以便条件知道如何排序。此外:这样的枚举开关不仅长而且难看。。。你应该完全避开它们。@jornverne是的,你是对的。我编辑了我的问题。请不要仅仅为了缩短代码而引入反射。为每个标准创建一个比较器,并根据选择的选项提供正确的比较器。第二个开关不应该是打开holder.criteria2或其他什么吗?这是一个很好的示例,说明了“告诉-不要问”原则。您不需要查询条件,然后决定如何排序;相反,您应该更改代码,以便条件知道如何排序。此外:这样的枚举开关不仅长而且难看。。。你应该完全避开它们。@jornverne是的,你是对的。我编辑了我的问题。