根据用户在 java8 中选择的 属性 对列表进行动态排序
Dynamically sort the list based on user selected property in java8
我有这个方法,效果很好,但是有没有更简洁的方法呢?
目前我已将比较器添加到地图中,并根据用户选择的值获得正确的比较器。
private Comparator<? super BusinessPartnerAssignmentDetail> getComparator(PortfolioFilterDto portfolioFilterDto){
Map<String, Comparator<? super BusinessPartnerAssignmentDetail>> sortingOptions = new HashMap<>();
sortingOptions.put("fieldOfficeDescription", Comparator.comparing(BusinessPartnerAssignmentDetail::getFieldOfficeDescription, Comparator.nullsLast(Comparator.naturalOrder())));
sortingOptions.put("locationDescription", Comparator.comparing(BusinessPartnerAssignmentDetail::getLocationDescription, Comparator.nullsLast(Comparator.reverseOrder())));
sortingOptions.put("segmentType", Comparator.comparing(BusinessPartnerAssignmentDetail::getSegmentType, Comparator.nullsLast(Comparator.reverseOrder())));
sortingOptions.put("displayName", Comparator.comparing(BusinessPartnerAssignmentDetail::getDisplayName, Comparator.nullsLast(Comparator.reverseOrder())));
return sortingOptions.get(portfolioFilterDto.getSortParameter());
}
然后我在列表中这样调用排序
businessPartnerAssignmentDetails.sort(getComparator(portfolioFilterDto));
每次调用该方法时都创建一个比较器映射是个坏主意。
相反,您可以 return switch case
中所需的比较器
switch (portfolioFilterDto.getSortParameter()){
case "fieldOfficeDescription" :
return Comparator.comparing(BusinessPartnerAssignmentDetail::getFieldOfficeDescription, Comparator.nullsLast(Comparator.naturalOrder()));
case "locationDescription" :
return Comparator.comparing(BusinessPartnerAssignmentDetail::getLocationDescription, Comparator.nullsLast(Comparator.reverseOrder()));
case "segmentType" :
return Comparator.comparing(BusinessPartnerAssignmentDetail::getSegmentType, Comparator.nullsLast(Comparator.reverseOrder()));
case "displayName" :
return Comparator.comparing(BusinessPartnerAssignmentDetail::getDisplayName, Comparator.nullsLast(Comparator.reverseOrder()));
default :
return null;
}
或者您可以在构造函数中将地图创建为全局字段,这样您就不会在每次撤销地图时都初始化地图。
我看到的唯一捷径是使用反射自动将 String
方法表示转换为 Function<? super BusinessPartnerAssignmentDetail, U>
。
重要提示: 此解决方案可能对 huuuge 数量的吸气剂和可能的组合有用。吸气剂必须是无形式参数的(标准吸气剂)。我宁愿坚持您当前的解决方案,这种方式更具可读性和可维护性,我认为这是优先事项。
解决方法及其说明:
- 使用
Class::getMethod
从 String
中提取 Method
。
- 从
Method
创建 Function<? super BusinessPartnerAssignmentDetail, U>
。
- 使用
Method::invoke
- 同一个方法调用抛出 2 个异常,因此为了清楚起见,lambda 表达式的创建最好将其包装到一个单独的方法 (
silentInv
) 中。
- Return 正确的比较器根据方法名称与名称列表(我建议将此列表设为静态)以自然或相反的顺序枯萎。
static List<String> naturalOrderList = Arrays.asList("fieldOfficeDescription");
static <U extends Comparable<U>> Comparator<? super BusinessPartnerAssignmentDetail>
getComparator(PortfolioFilterDto p) throws NoSuchMethodException
{
/** (1) **/
Method method = BusinessPartnerAssignmentDetail.class.getMethod(p.getSortParameter());
/** (2) **/
Function<? super BusinessPartnerAssignmentDetail, U> function = silentInv(method);
/** (3) **/
Comparator<U> order = methodsWithNaturalOrders.contains(method.getName())
? Comparator.naturalOrder()
: Comparator.reverseOrder();
return Comparator.comparing(function, Comparator.nullsLast(order));
}
@SuppressWarnings("unchecked")
static <U extends Comparable<U>> Function<? super BusinessPartnerAssignmentDetail, U>
silentInv(Method method)
{
/** (2) The necessary try-catch wrapping, the exception should never be thrown **/
return bpad -> {
try {
return (U) method.invoke(bpad);
} catch (Exception e) {
String message = "Invalid method name " + method.getName();
throw new IllegalArgumentException(message , e);
}
};
}
提示:尽可能使用较短的 class 名称:)
尝试使用 ENUM 来排序选项并使用 switch case 来获取特定的比较器:
带枚举过滤器选项的 DTO
public class PortfolioFilterDto {
/*your existing code
*
*
* */
PortfolioFilterDtoOptions sortParameter;
enum PortfolioFilterDtoOptions {
fieldOfficeDescription, locationDescription, segmentType, displayName
}
public PortfolioFilterDtoOptions getSortParameter() {
return this.sortParameter;
}
}
您动态获取过滤器选项的方法
private Comparator<? super BusinessPartnerAssignmentDetail> getComparator(PortfolioFilterDto portfolioFilterDto) {
switch (PortfolioFilterDto.getSortParameter()) {
case PortfolioFilterDtoOptions.fieldOfficeDescription:
return Comparator.comparing(BusinessPartnerAssignmentDetail::getFieldOfficeDescription, Comparator.nullsLast(Comparator.naturalOrder()));
case PortfolioFilterDtoOptions.locationDescription:
return Comparator.comparing(BusinessPartnerAssignmentDetail::getLocationDescription, Comparator.nullsLast(Comparator.reverseOrder()));
case PortfolioFilterDtoOptions.segmentType:
return Comparator.comparing(BusinessPartnerAssignmentDetail::getSegmentType, Comparator.nullsLast(Comparator.reverseOrder()));
case PortfolioFilterDtoOptions.displayName:
return Comparator.comparing(BusinessPartnerAssignmentDetail::getDisplayName, Comparator.nullsLast(Comparator.reverseOrder()));
default:
// put default filter here
return null;
}
}
你可以像 Sourin 说的那样将所有这些都包装在一个 enum
中,但是你可以用更多的功能来丰富它,比如实际比较。
enum AssignmentFilter implements Comparator<BusinessPartnerAssignmentDetail> {
fieldOfficeDescription(BusinessPartnerAssignmentDetail::getFieldOfficeDescription, Comparator.naturalOrder()),
locationDescription(BusinessPartnerAssignmentDetail::getLocationDescription),
segmentType(BusinessPartnerAssignmentDetail::getSegmentType),
displayName(BusinessPartnerAssignmentDetail::getDisplayName);
private Function<BusinessPartnerAssignmentDetail, Comparable<? super BusinessPartnerAssignmentDetail>> compareByKey;
AssignmentFilter(Function<BusinessPartnerAssignmentDetail, Comparable<? super BusinessPartnerAssignmentDetail>> byKey, Comparator<BusinessPartnerAssignmentDetail> whenNull) {
compareByKey = Comparator.comparing(byKey, Comparator.nullsLast(whenNull));
}
AssignmentFilter(Function<BusinessPartnerAssignmentDetail, Comparable<? super BusinessPartnerAssignmentDetail>> byKey) {
this(byKey, Comparator.reverseOrder());
}
public int compare(BusinessPartnerAssignmentDetail bpad1, BusinessPartnerAssignmentDetail bpad1) {
return comparator().compare(bpad1, bpad2);
}
}
你可以通过businessPartnerAssignmentDetails.sort(AssingmentFilter.valueOf(portfolioFilterDto.getSortParameter()))
调用它。
这是否比仅填充地图更好,由您决定。
我有这个方法,效果很好,但是有没有更简洁的方法呢?
目前我已将比较器添加到地图中,并根据用户选择的值获得正确的比较器。
private Comparator<? super BusinessPartnerAssignmentDetail> getComparator(PortfolioFilterDto portfolioFilterDto){
Map<String, Comparator<? super BusinessPartnerAssignmentDetail>> sortingOptions = new HashMap<>();
sortingOptions.put("fieldOfficeDescription", Comparator.comparing(BusinessPartnerAssignmentDetail::getFieldOfficeDescription, Comparator.nullsLast(Comparator.naturalOrder())));
sortingOptions.put("locationDescription", Comparator.comparing(BusinessPartnerAssignmentDetail::getLocationDescription, Comparator.nullsLast(Comparator.reverseOrder())));
sortingOptions.put("segmentType", Comparator.comparing(BusinessPartnerAssignmentDetail::getSegmentType, Comparator.nullsLast(Comparator.reverseOrder())));
sortingOptions.put("displayName", Comparator.comparing(BusinessPartnerAssignmentDetail::getDisplayName, Comparator.nullsLast(Comparator.reverseOrder())));
return sortingOptions.get(portfolioFilterDto.getSortParameter());
}
然后我在列表中这样调用排序
businessPartnerAssignmentDetails.sort(getComparator(portfolioFilterDto));
每次调用该方法时都创建一个比较器映射是个坏主意。
相反,您可以 return switch case
switch (portfolioFilterDto.getSortParameter()){
case "fieldOfficeDescription" :
return Comparator.comparing(BusinessPartnerAssignmentDetail::getFieldOfficeDescription, Comparator.nullsLast(Comparator.naturalOrder()));
case "locationDescription" :
return Comparator.comparing(BusinessPartnerAssignmentDetail::getLocationDescription, Comparator.nullsLast(Comparator.reverseOrder()));
case "segmentType" :
return Comparator.comparing(BusinessPartnerAssignmentDetail::getSegmentType, Comparator.nullsLast(Comparator.reverseOrder()));
case "displayName" :
return Comparator.comparing(BusinessPartnerAssignmentDetail::getDisplayName, Comparator.nullsLast(Comparator.reverseOrder()));
default :
return null;
}
或者您可以在构造函数中将地图创建为全局字段,这样您就不会在每次撤销地图时都初始化地图。
我看到的唯一捷径是使用反射自动将 String
方法表示转换为 Function<? super BusinessPartnerAssignmentDetail, U>
。
重要提示: 此解决方案可能对 huuuge 数量的吸气剂和可能的组合有用。吸气剂必须是无形式参数的(标准吸气剂)。我宁愿坚持您当前的解决方案,这种方式更具可读性和可维护性,我认为这是优先事项。
解决方法及其说明:
- 使用
Class::getMethod
从String
中提取Method
。 - 从
Method
创建Function<? super BusinessPartnerAssignmentDetail, U>
。- 使用
Method::invoke
- 同一个方法调用抛出 2 个异常,因此为了清楚起见,lambda 表达式的创建最好将其包装到一个单独的方法 (
silentInv
) 中。
- 使用
- Return 正确的比较器根据方法名称与名称列表(我建议将此列表设为静态)以自然或相反的顺序枯萎。
static List<String> naturalOrderList = Arrays.asList("fieldOfficeDescription");
static <U extends Comparable<U>> Comparator<? super BusinessPartnerAssignmentDetail>
getComparator(PortfolioFilterDto p) throws NoSuchMethodException
{
/** (1) **/
Method method = BusinessPartnerAssignmentDetail.class.getMethod(p.getSortParameter());
/** (2) **/
Function<? super BusinessPartnerAssignmentDetail, U> function = silentInv(method);
/** (3) **/
Comparator<U> order = methodsWithNaturalOrders.contains(method.getName())
? Comparator.naturalOrder()
: Comparator.reverseOrder();
return Comparator.comparing(function, Comparator.nullsLast(order));
}
@SuppressWarnings("unchecked")
static <U extends Comparable<U>> Function<? super BusinessPartnerAssignmentDetail, U>
silentInv(Method method)
{
/** (2) The necessary try-catch wrapping, the exception should never be thrown **/
return bpad -> {
try {
return (U) method.invoke(bpad);
} catch (Exception e) {
String message = "Invalid method name " + method.getName();
throw new IllegalArgumentException(message , e);
}
};
}
提示:尽可能使用较短的 class 名称:)
尝试使用 ENUM 来排序选项并使用 switch case 来获取特定的比较器:
带枚举过滤器选项的 DTO
public class PortfolioFilterDto {
/*your existing code
*
*
* */
PortfolioFilterDtoOptions sortParameter;
enum PortfolioFilterDtoOptions {
fieldOfficeDescription, locationDescription, segmentType, displayName
}
public PortfolioFilterDtoOptions getSortParameter() {
return this.sortParameter;
}
}
您动态获取过滤器选项的方法
private Comparator<? super BusinessPartnerAssignmentDetail> getComparator(PortfolioFilterDto portfolioFilterDto) {
switch (PortfolioFilterDto.getSortParameter()) {
case PortfolioFilterDtoOptions.fieldOfficeDescription:
return Comparator.comparing(BusinessPartnerAssignmentDetail::getFieldOfficeDescription, Comparator.nullsLast(Comparator.naturalOrder()));
case PortfolioFilterDtoOptions.locationDescription:
return Comparator.comparing(BusinessPartnerAssignmentDetail::getLocationDescription, Comparator.nullsLast(Comparator.reverseOrder()));
case PortfolioFilterDtoOptions.segmentType:
return Comparator.comparing(BusinessPartnerAssignmentDetail::getSegmentType, Comparator.nullsLast(Comparator.reverseOrder()));
case PortfolioFilterDtoOptions.displayName:
return Comparator.comparing(BusinessPartnerAssignmentDetail::getDisplayName, Comparator.nullsLast(Comparator.reverseOrder()));
default:
// put default filter here
return null;
}
}
你可以像 Sourin 说的那样将所有这些都包装在一个 enum
中,但是你可以用更多的功能来丰富它,比如实际比较。
enum AssignmentFilter implements Comparator<BusinessPartnerAssignmentDetail> {
fieldOfficeDescription(BusinessPartnerAssignmentDetail::getFieldOfficeDescription, Comparator.naturalOrder()),
locationDescription(BusinessPartnerAssignmentDetail::getLocationDescription),
segmentType(BusinessPartnerAssignmentDetail::getSegmentType),
displayName(BusinessPartnerAssignmentDetail::getDisplayName);
private Function<BusinessPartnerAssignmentDetail, Comparable<? super BusinessPartnerAssignmentDetail>> compareByKey;
AssignmentFilter(Function<BusinessPartnerAssignmentDetail, Comparable<? super BusinessPartnerAssignmentDetail>> byKey, Comparator<BusinessPartnerAssignmentDetail> whenNull) {
compareByKey = Comparator.comparing(byKey, Comparator.nullsLast(whenNull));
}
AssignmentFilter(Function<BusinessPartnerAssignmentDetail, Comparable<? super BusinessPartnerAssignmentDetail>> byKey) {
this(byKey, Comparator.reverseOrder());
}
public int compare(BusinessPartnerAssignmentDetail bpad1, BusinessPartnerAssignmentDetail bpad1) {
return comparator().compare(bpad1, bpad2);
}
}
你可以通过businessPartnerAssignmentDetails.sort(AssingmentFilter.valueOf(portfolioFilterDto.getSortParameter()))
调用它。
这是否比仅填充地图更好,由您决定。