【问题标题】:Java reflection inside stream's filter流过滤器内的Java反射
【发布时间】:2020-05-16 22:04:02
【问题描述】:

我有一个 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&lt;Employee&gt;,类类型@ 987654327@,我们要过滤哪个字段 (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());
}

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

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

但是有了这个我得到了 NPE

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

您能否帮我创建一个通用方法,该方法可以调用任何 POJO 的列表,并且过滤器可以应用于其任何 String 类型的方法?

【问题讨论】:

    标签: java generics reflection java-8 java-stream


    【解决方案1】:

    调用应该发生在蒸过的项目上,而不是类本身。方法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。先提取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 进行比较时,您想添加一些额外的比较条件。

    【讨论】:

      猜你喜欢
      • 2018-08-08
      • 1970-01-01
      • 2021-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-18
      • 1970-01-01
      • 2019-01-30
      相关资源
      最近更新 更多