我有一个名为 tasks 的 ArrayList<Task> ,我想要打印它,根据 Task 对象的每个字段进行排序。 任务类具有三个私有(private)字段 { String title, Date date, String project }。 该类有一些公共(public) get 方法,允许其他类读取字段 { getTitle(), getDate(), getProject(), <强>getTaskDetails() }.
我有一个简单的方法,使用流来排序和打印 ArryaList 任务:
tasks.stream()
.sorted(Comparator.comparing(Task::getProject))
.map(Task::getTaskDetails)
.forEach(System.out::println);
为了根据每个不同的 getter 方法进行排序,我不想创建 3 种不同的方法,而是使用 Reflection API。但我在调用 Comparator 比较方法中的方法( getTitle()、getDate()、getProject() )时遇到问题:
使用导入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);
这可能吗?或者有更简单的解决方案吗?
只找到这个question但没有解决我的问题。
感谢您的任何反馈。
最佳答案
您链接到的答案基本上包含核心思想,即使它指的是字段(“属性”)而不是方法:创建一种从对象获取所需值的方法,然后简单地比较这些值两个物体。
有人可以将其视为重复项,但我不确定。
无论如何:
您应该仔细考虑反射是否是正确的方法。
在没有反射的情况下生成所需的比较器可能会更优雅(即更少黑客)。这可以是一个枚举,您可以将正确的 Comparator
附加到每个枚举值:
enum TaskProperty {
TITLE(comparatorForTitle),
DATE(comparatorForDate), ...
}
// Using it:
tasks.stream().sorted(TaskProperty.TITLE.getComparator()).forEach(...);
或者也许(类型安全性较差,但更灵活),使用可以通过字符串查找它们的 map ,如
// 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(...);
<小时/>
如果您仔细考虑过这一点,并且确实想要使用基于反射的方法:
您可以创建一个实用方法来获取给定对象的特定方法的返回值。然后创建一个比较器,为给定对象调用此方法,并比较返回值。为了灵 active ,您可以将返回值传递给下游比较器(默认情况下可以是 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;
}
}
}
关于java - 调用Comparator比较方法中的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58304381/