集合Java,带反射的列表排序
我希望允许按类中的每个字段进行排序,而不必编写switch/if语句。 我的想法是通过名称找到与给定字符串值匹配的字段,然后使用流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接口,但我不确定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解决方案的我的代码:
用户实体(可为空)
@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());
}
}));
}
# 1 楼答案
您可以为任何类using reflection的任何字段自动创建比较器,但最好创建特定的比较器(将进行类型检查)
您的实体是一个带有普通字段的普通类。那么,通常的Java排序机制应该可以完成这项工作:
基本上,如果为每个字段定义一个比较器(甚至是实体中的深字段):
可以使用复杂的排序表达式进行排序:
一个完整的例子可以是
有输出
进入
SearchCriteria
类的criteria字段是Comparator<MyEntity>
类型的字段,或者是使用枚举或解析字符串表达式等的映射# 2 楼答案
MyEntity
不应实现Comparable
。正是字段,您将根据这些字段对MyEntity
对象列表进行排序,它们需要是Comparable
。例如,如果按字段user
排序,这是一个UserEntity
,那么UserEntity
是需要可比较的,而不是MyEntity
lambda的工作应该只是检查字段是否确实是
Comparable
,如果不是,则抛出异常但是,由于您在编译时不知道字段的类型,因此必须在这里使用原始类型。
comparing
调用如下所示: