java - 在 Comparator 比较方法中调用方法
问题描述
我有一个要打印的 ArrayList< Task > 命名任务,根据Task对象的每个字段进行排序。任务类有三个私有字段 { String title , Date date , String project }。该类有一些公共的 get 方法,允许其他类读取字段 { getTitle()、getDate()、getProject()、getTaskDetails() }。
我有一个简单的方法,它使用流对 ArryaList 任务进行排序和打印:
tasks.stream()
.sorted(Comparator.comparing(Task::getProject))
.map(Task::getTaskDetails)
.forEach(System.out::println);
我想使用反射 API,而不是创建 3 种不同的方法来根据每个不同的 getter 方法进行排序。但我无法在 Comparator 比较方法中调用方法( getTitle()、getDate()、getProject() ):
用过的import java.lang.reflect.Method;
声明方法Method taskMethod = Task.class.getDeclaredMethod(methodName);
,其中methodName将是使用方法名称(“getTitle”或“getDate”或“getProject”)接收的参数字符串。
然后尝试做这样的事情,但没有锻炼:
tasks.stream()
.sorted(Comparator.comparing(task -> {
try {
taskMethod.invoke(task);
} catch (Exception e) {
e.printStackTrace();
}
}))
.map(Task::getTaskDetails)
.forEach(System.out::println);
这可能吗?或者有没有更简单的解决方案?
只发现了这个问题,但没有解决我的问题。
感谢您的任何反馈。
解决方案
您链接到的答案基本上包含核心思想,即使它引用字段(“属性”)而不是方法:创建一种从对象获取所需值的方法,然后简单地比较两个对象的这些值。
人们可以认为它是重复的,但我不确定。
任何状况之下:
您应该仔细考虑反射是否是正确的方法。
在没有反射的情况下生成所需的比较器可能会更优雅(即更少hacky)。这可能是一个枚举,您可以在其中将正确的属性附加Comparator
到每个枚举值:
enum TaskProperty {
TITLE(comparatorForTitle),
DATE(comparatorForDate), ...
}
// Using it:
tasks.stream().sorted(TaskProperty.TITLE.getComparator()).forEach(...);
或者也许(更少类型安全,但更灵活一点),使用可以通过字符串查找它们的地图,如
// Put all comparators into a map
map.put("getDate", compareTaskByDate);
...
// Later, use the string to pick up the comparator from the map:
tasks.stream().sorted(map.get("getDate")).forEach(...);
如果您仔细考虑了这一点,并且真的想使用基于反射的方法:
您可以创建一个实用方法来获取给定对象的某个方法的返回值。然后创建一个为给定对象调用此方法的比较器,并比较返回值。为了灵活起见,您可以将返回值传递给下游比较器(naturalOrder
默认情况下)。
此处显示了如何完成此操作的示例。但是捕获的异常列表getOptional
应该清楚地表明很多事情都可能在这里出错,您应该真正考虑一种不同的方法:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class SortWithReflection
{
public static void main(String[] args)
{
List<Task> tasks = new ArrayList<Task>();
tasks.add(new Task("AAA", 222));
tasks.add(new Task("BBB", 333));
tasks.add(new Task("CCC", 111));
System.out.println("By getTitle:");
tasks.stream()
.sorted(by("getTitle"))
.forEach(System.out::println);
System.out.println("By getDate:");
tasks.stream()
.sorted(by("getDate"))
.forEach(System.out::println);
System.out.println("By getDate, reversed");
tasks.stream()
.sorted(by("getDate", Comparator.naturalOrder().reversed()))
.forEach(System.out::println);
}
private static <T> Comparator<T> by(String methodName)
{
return by(methodName, Comparator.naturalOrder());
}
private static <T> Comparator<T> by(
String methodName, Comparator<?> downstream)
{
@SuppressWarnings("unchecked")
Comparator<Object> uncheckedDownstream =
(Comparator<Object>) downstream;
return (t0, t1) ->
{
Object r0 = getOptional(t0, methodName);
Object r1 = getOptional(t1, methodName);
return uncheckedDownstream.compare(r0, r1);
};
}
private static <T> T getOptional(
Object instance, String methodName)
{
try
{
Class<?> type = instance.getClass();
Method method = type.getDeclaredMethod(methodName);
Object object = method.invoke(instance);
@SuppressWarnings("unchecked")
T result = (T)object;
return result;
}
catch (NoSuchMethodException
| SecurityException
| IllegalAccessException
| IllegalArgumentException
| InvocationTargetException
| ClassCastException e)
{
e.printStackTrace();
return null;
}
}
static class Task
{
String title;
Integer date;
Task(String title, Integer date)
{
this.title = title;
this.date = date;
}
String getTitle()
{
return title;
}
Integer getDate()
{
return date;
}
@Override
public String toString()
{
return title + ": " + date;
}
}
}
推荐阅读
- robotframework - 机器人框架。等到关键字成功 5m 10s {keyword {keyword {keyword}}}
- c++ - 用于 QT/C++ 开发的 QTCreator 的免费替代品
- python - BufferError:本地:Python 中的队列已满
- webgl - 渲染警告:绑定到纹理单元 0 的纹理不可渲染。它可能是非 2 的幂或具有不兼容的纹理过滤(也许)?
- typescript - 如何在 Typescript 中使用动态键定义类型安全集合并且仍然具有智能感知支持
- c# - 使用 EF Core 在 ASP.NET Core 中执行 CRUD 时,我应该单独使用 DbContext 还是 DbSet
- python - 使用熊猫python读取csv文件时出错
- paypal - 使用智能按钮集成禁用 PayPal 结帐按钮
- java - USACO 培训挤奶时间(最长非挤奶时间) - java
- java - Java 8:带有 where 条件的 Lambda 表达式