Java,使用反射进行列表排序

标签 java collections java-stream

我希望允许按类中的每个字段进行排序,而不必编写 switch/if 语句。 我的想法是找到按名称匹配给定字符串值的字段,然后使用 Stream API 进行整齐排序。 IntelliJ 尖叫着说我需要用 try-catch 包围它,所以它看起来不太整齐,但这并不重要,因为它不起作用。

    private List<MyEntity> getSorted(List<MyEntity> list, SearchCriteria criteria) {
        Field sortByField = findFieldInListByName(getFieldList(MyEntity.class), criteria.getSortBy());
        return list.stream().sorted(Comparator.comparing(entity-> {
            try {
                return (MyEntity) sortByField.get(entity);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return entity;
        })).collect(Collectors.toList());
    }

在 MyEntity 类中,我添加了 Comparable 接口(interface),但我不确定 Compare() 的主体中应该包含什么,因为我不想指定如何比较对象,因为它会根据所选的排序而改变。

编辑:添加以下实体:

@Data
@Entity
@Table(name = "role_management", schema = "mdr")
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode

public class MyEntity implements Comparable{

    @Id
    @Column(name = "uuid", unique = true, insertable = false, updatable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private UUID uuid;

    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false)
    private UserEntity user;

    @Basic
    @NonNull
    @Column(name = "role")
    private String role;

    @Basic
    @Column(name = "action")
    @Enumerated(EnumType.STRING)
    private RoleAction action;

    @Basic
    @Column(name = "goal")
    @Enumerated(EnumType.STRING)
    private RoleGoal goal;

    @Column(name = "date")
    private LocalDateTime date;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "reporter_id", referencedColumnName = "uuid")
    private UserEntity reporter;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "authorizer_id", referencedColumnName = "uuid")
    private UserEntity authorizer;

    @Basic
    @Column(name = "ezd")
    private String ezd;

    @Basic
    @Column(name = "is_last")
    private boolean isMostRecent;

    @Override
    public int compareTo(Object o) {
        return 0;
    }
}

编辑2:我基于@Sweeper解决方案的代码:

UserEntity(可为空)

    @Override
    public int compareTo(UserEntity other) {
        if (other == null) {
            return 1;
        }
        return this.getMail().compareTo(other.getMail());
    }

比较器:

    public static Comparator getSortComparator(Field sortByField) {
        return Comparator.nullsLast(Comparator.comparing(entity -> {
            try {
                Object fieldValue = sortByField.get(entity);
                if (!(fieldValue instanceof Comparable<?>) && fieldValue != null) {
                    throw new IllegalArgumentException("...");
                }
                return (Comparable) fieldValue;
            } catch (IllegalAccessException e) {
                throw new MdrCommonException(e.getLocalizedMessage());
            }
        }));
    }

最佳答案

MyEntity 不应实现 Comparable。您将通过字段MyEntity 对象列表进行排序,并且需要Comparable。例如,如果您按字段 user 排序,该字段是一个 UserEntity,则 UserEntity 是需要比较的内容,而不是MyEntity

lambda 的工作应该只是检查字段是否确实可比较,如果不是,则抛出异常。

由于您在编译时不知道字段的类型,因此您必须在此处使用原始类型。 比较调用如下所示:

Comparator.comparing(entity -> {
    try {
        Object fieldValue = sortByField.get(entity);

        // This check still passes if the type of fieldValue implements Comparable<U>, 
        // where U is an unrelated type from the type of fieldValue, but this is the
        // best we can do here, since we don't know the type of field at compile time
        if (!(fieldValue instanceof Comparable<?>) && fieldValue != null) {
            throw new IllegalArgumentException("Field is not comparable!");
        }
        return (Comparable)fieldValue;
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    }
})

关于Java,使用反射进行列表排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68646884/

相关文章:

c++ - 有什么理由去寻找继承/多态性的替代方案吗?

c# - 如何检查 ObservableCollection 中的重复项?

c# - Linq 获取并置相等对象的集合

java-8 - 将 Java 8 流式映射函数作为参数传递

java - startsWith() 无法与 '§' 字符正常工作

java - Hibernate 性能最佳实践?

java - Hibernate:为两个不同的类映射同一列

java - 将函数和参数传递给另一个函数

java - 使用 java 8 计算列表中对象的属性

java - 将 boolean 值序列化为 "1"和 "0"而不是 "true"和 "false"