在java8中根据用户选择的属性对列表进行动态排序。

问题描述 投票:0回答:2

我有这个方法,效果不错,但是有没有更简洁的方法?

目前,我在地图上添加了比较器,并根据用户选择的值获得正确的比较器。

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));
java lambda java-8 comparator
2个回答
2
投票

我看到的唯一的捷径是自动转换 String 的方法表示。Function<? super BusinessPartnerAssignmentDetail, U> 使用反射。

重要的是。 这个解决方案可能在以下情况下有用 硕大 获取器的数量和可能的组合。获取器必须是无形式参数的(标准获取器)。我更倾向于坚持你目前的解决方案,这是更可读和可维护的方式,我认为这是优先考虑的。

解决方案和它的描述。

  1. 提取 Method 来自 String 使用 Class::getMethod.
  2. 创建 Function<? super BusinessPartnerAssignmentDetail, U>Method.
    • 使用 Method::invoke
    • 同样的方法调用会抛出2个异常,所以创建lambda表达式最好把它包装成一个单独的方法(silentInv)为了清晰起见。
  3. 根据方法名称与名称列表比较,以自然或反向顺序返回正确的比较器凋零器(我建议把这个列表做成静态的)。
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);
        }
    };
}

提示:如果可能的话,使用较短的类名。 如果可能的话,使用更短的类名:)


0
投票

每次方法被调用时创建一个比较器的映射是一个坏主意。

相反,你可以在方法中返回所需的比较器。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;
    }

或者你可以在构造函数里面创建地图作为一个全局字段,那么你就不会在每次撤销地图的时候初始化它。


0
投票

试着使用一个ENUM作为排序选项,并使用一个开关案例来获得特定的比较器。

DTO与Enum过滤选项

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;
    }
}

0
投票

你可以把这些都包在一个 enum就像Sourin说的那样,但你可以用更多的功能来丰富它,比如实际比较。

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())).

是否比单纯的填图好,由你决定。

© www.soinside.com 2019 - 2024. All rights reserved.