流过滤器中的 Java 反射

标签 java generics reflection java-8 java-stream

我有一个 Java POJO:

public class Event {
    private String id;
    private String name;
    private Long time;
}

我创建的一个简单的过滤方法是:

public static List<Event> simpleFilter(List<Event> eventList, String value) {
    return eventList.stream().filter(Event -> Event.getName().equals(value)).collect(Collectors.toList());
}

现在我的任务是创建一个通用方法而不是 simpleFilter它可以应用于任何 Java POJO 对象及其任何字段。例如,如果将来有一个新的 Java 对象 Employee我们想过滤它的字符串字段 employeeDepartment ,我们可以通过传递 Java 对象列表(List<Employee>,类类型Employee.class),我们要过滤的字段(getEmployeeDepartment)和什么值("Computer")来使用相同的通用过滤方法。

我创建了一个方法定义:

public static <T> List<T> genericStringFilterOnList(List<T> list, Class<T> c, String methodName, String value) {
}

调用者看起来像:

//events is List<Event>
//getName is the method in Event on which I want to filter
//e2 is value which I want to filter
genericStringFilterOnList(events, Event.class, "getName", "e2")

我的实现是:

public static <T> List<T> genericStringFilterOnList(List<T> list, Class<T> c, String methodName, String value) {
    return list.stream().filter(m -> {
        try {
            return c.getMethod(methodName, null).invoke(c).equals(value);
        } catch (IllegalAccessException e) {
        } catch (IllegalArgumentException e) {
        } catch (InvocationTargetException e) {
        } catch (NoSuchMethodException e) {
        } catch (SecurityException e) {
        }
        return false;
    }).collect(Collectors.toList());
}

所有这些catch都是IDE因为checked exception产生的。 这似乎不起作用,因为它返回一个空列表。 我想在这里做的是 - 使用类类型(即 Event.class ),我使用反射获取方法名称,然后调用该方法,然后调用它基本上是调用 getName() Event 类的方法,然后等于。我也试过这个-

return c.getMethod(methodName, null).invoke(c.newInstance()).equals(value);

但是有了这个我就得到了 NPE

}).collect(Collectors.toList());

能否请您帮我创建一个通用方法,该方法可以为任何 POJO 的列表调用,并且可以在其任何字符串类型方法上应用过滤器?

最佳答案

调用应该发生在蒸的项目上,而不是类本身。方法Method::invoke(Object obj, Object... args)有两个参数:

  • obj - 从中​​调用基础方法的对象
  • args - 用于方法调用的参数

更改行:

return c.getMethod(methodName, null).invoke(c).equals(value);

.. 到:

return c.getMethod(methodName, null).invoke(m).equals(value);

混淆来自一个字母的变量名(参见下面的解决方案)。


应简化整个解决方案。您不想通过反射为流管道中存在的每个对象提取完全相同的 Method。首先提取方法并重用它:

static <T> List<T> genericStringFilterOnList(List<T> list, Class<T> clazz, String method, String value) {
    try {
        // reflection invoked just once
        Method method = clazz.getMethod(method, null);
        // now streaming of the n items
        return list.stream().filter(item -> {
            try { 
                return value.equals(method.invoke(item));
            } catch (IllegalAccessException | InvocationTargetException e) {}
            return false;
        }).collect(Collectors.toList());
    } catch (NoSuchMethodException e) {}
    return Collections.emptyList();
}

(超出此问题的范围):请注意,调用的方法返回 null 的可能性高于传递的 value 的可能性,因此我会选择value.equals(method.invoke(item))。也许,当要比较的两个值都为 null 时,您想添加一些额外的比较条件。

关于流过滤器中的 Java 反射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61844191/

相关文章:

java - 在java中将二维数组的列复制为一维数组?

java - eclipse 不显示编译错误,但 ant 编译失败

c# - C# 中是否有带参数约束的泛型构造函数?

java - 在 JUnit 的测试类中定义内部类时出错

c# - 从 NameValueCollection 设置类的属性

Java, boolean 值可以从 boolean 值赋值,反之亦然吗?

java-jsf 库,具有良好的移动浏览器支持

java - 如何在发出请求之前检查互联网连接

Java - 外部类内部的内部类数组

c# - 当我不知道 T 是什么时,如何在另一种方法中使用泛型类?