我希望允许按类中的每个字段进行排序,而不必编写 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/