Java 为排序构建一个特定的自定义比较器

Posted

技术标签:

【中文标题】Java 为排序构建一个特定的自定义比较器【英文标题】:Java Building a specific custom Comparator for Sorting 【发布时间】:2013-07-22 13:23:43 【问题描述】:

我正在开发一个 ORM 系统(对象关系映射,基本上是 java 类中的一个包装器,因此我不需要直接使用 SQL 代码)

这个问题是关于通过指定约束在表中搜索:

public final List<B> search(final AbstractConstraint... c) throws SearchException 
    if (c.length == 0) 
        throw new IllegalArgumentException("orm.Manager.search: c.length == 0");
    
    try 
        List<B> beans = new ArrayList<>();

        for (AbstractConstraint constraint : c) 
            try (PreparedStatement ps = new QueryBuilder(connection, tableName(), getPaths(), searchQuery()).add(constraint).build();
                    ResultSet rs = ps.executeQuery()) 
                while (rs.next()) 
                    beans.add(createBean(rs));
                
            
        

        if (c.length > 1) 
            boolean sorting = true;
            Field field = c[0].getField();
            Order order = c[0].getOrder();
            for (int i = 1; i < c.length; i++) 
                Field currentField = c[i].getField();
                Order currentOrder = c[i].getOrder();
                if (!field.equals(currentField) || !order.equals(currentOrder)) 
                    sorting = false;
                    break;
                
            
            if (sorting) 
                //sort on field with comparator of supertype
            
        

        return beans;
     catch (SQLException ex) 
        Logger.getLogger(Manager.class.getName()).log(Level.SEVERE, null, ex);
        throw new SearchException(ex);
    

通常,AbstractConstraint 本身负责处理顺序。但是,如果您使用多个 AbstractConstraints(基本上是我的 SQL OR 对应),则存在一种特殊情况。如果其中两个单独的 AbstractConstraints(已经排序)共享相同的排序,那么生成的 List&lt;B&gt; 应该也是排序的,并且不包含两个堆叠在一起的有序列表。

我该怎么做呢?这是我所知道的:

Field 对象,指定应搜索的字段,这是对 SQL 数据库中表中列的直接引用。 Order 对象

所以我认为(在我当前的实现中),列(因此字段)可以具有以下值:

字符串(在 SQL varchar 中) 整数(在 SQL 整数中) 日期(在 SQL 日期时间中) BigInteger(SQL 十进制)

而且顺序是升序或降序。

我需要如何扩展我的Field 类来捕获列的类型?这就是 Field 当前的全部内容:

public interface Field 
    public String getFieldName();

我该如何写Comparator?实际上,我什至必须编写Comparator 还是应该让Field 以某种方式实现Comparable

我希望这个问题是可以理解的,并期待任何答复。

编辑:添加Field的具体实现示例:

public enum InvoiceFields implements Field 
    invoiceId("invoices.invoiceId"),
    businessPartnerId("invoices.businessPartnerId"),
    invoiceNumber("invoices.invoiceNumber"),
    invoiceDate("invoices.invoiceDate"),
    priceExclVAT("invoices.priceExclVAT"),
    VAT("invoices.VAT"),
    priceInclVAT("invoices.priceInclVAT"),
    paymentDiscount("invoices.paymentDiscount"),
    status("invoices.status");

    private final String enumName;

    private InvoiceFields(final String enumName) 
        this.enumName = enumName;
    

    @Override
    public String getFieldName() 
        return enumName;
    

【问题讨论】:

您听说过 JPA,对吧? :)。 @ColinMorelli 是的,忘了补充一点,我或多或少只是对尝试自己写一些东西感兴趣。它从一个小项目开始,因为我认为 JPA 很难,我还不想让我的项目死掉:P 您对可以使用的数据结构有任何限制吗?例如。为什么不让 sql 处理排序?为什么 Field 实现是 enum !? 目前的限制是SQL每次只能处理一个AbstractConstraint,重写会很麻烦。 Field 是一个枚举,因为您现在可以指定 AccountConstraint accountConstraint = new AccountConstraint.Builder().like().username("%e%").orderBy(AccountFields.age, Order.ASCENDING).build(); 如果您想检索用户名中带有 e 的所有帐户并按年龄排序。 createBean() 返回什么类?简单的 POJO? (在您的回答中请使用@c.s.,以便我收到您的评论通知) 【参考方案1】:

我认为你想要一个抽象类。即然后为每个不同类型的字段创建子类。

public abstract class Field implements Comparable<Field> 

public abstract String getFieldName();

public int compareTo(Field field) 
return 0;


【讨论】:

这并不关心compareTo 的实际实现,这在很大程度上取决于Field 的类型,并且也应该在某处捕获。 你不能只覆盖子类中的 compareTo 吗? 在我的 OP 末尾添加了一个示例。不要以为我能做到。

以上是关于Java 为排序构建一个特定的自定义比较器的主要内容,如果未能解决你的问题,请参考以下文章

Android - 是不是可以使用 Comparator.comparing 而不是 API < 24 上的自定义比较器对列表进行排序?

Java 数组排序:获取数组索引的排序列表的快速方法

Collection接口下的Set接口TreeSet类中的自定义比较策略

如何在排序对象列表时解决自定义比较器的意外行为?

如何全局构建自定义比较器函数?

SQL Server的自定义排序功能