用java中的反射谓词

时间:2015-04-08 05:23:29

标签: java java-8

class DataObject
{
String attr1;
String attr2;
String attr3;

// getters of three fields(getAttr1(),getAttr2() and getAttr3())
// setters of three fields(setAttr1(),setAttr2() and setAttr3())
}   

     List<DataObject> result = null;//Output List of objects of 'DataObject' class

    List<DataObject> dataObjectList; // Input List of objects of 'DataObject'class. 
Predicate<DataObject>  first= e -> e.getAttr1().equals("Value1_1");
result = dataObjectList.stream().filter(first).collect(Collectors.toList());

我想根据运行时的条件过滤我的对象列表(这里的条件是attr1 =“Value1_1”)。我的问题是我只在运行时获取方法名称(可以是getAttr1()或getAttr2()或getAttr3()或任何其他函数)。我用反射来解决这个问题。

Class<?> cls = Class.forName("com.example.java.DataObject");        
Class<?> noparams[] = {};
Method method = cls.getDeclaredMethod("getAttr1", noparams);
Predicate<DataObject>  first= e -> method.equals("Value1_1");

但代码不会提供所需的结果。请在反思中更正我的代码。另外请给我任何替代解决方案。

2 个答案:

答案 0 :(得分:3)

您必须实际调用该方法以使用Method#invoke()方法返回结果。现在,您只是比较Method对象。将其更改为:

Predicate<DataObject>  first= e -> method.invoke(e).equals("Value1_1");

但这真是一种奇怪的方式。如果你能说明你到底想要做什么,我相信还有其他办法。

答案 1 :(得分:3)

你是否因为反思而死定?反思往往比它的价值更麻烦。怎么样:

class DataObject {
    static enum Attr {
        Attr1(DataObject::getAttr1),
        Attr2(DataObject::getAttr2),
        Attr3(DataObject::getAttr3),
        Attr4(DataObject::getAttr4);

        final Function<DataObject, Object> getter;

        Attr(Function<DataObject, Object> getter) {
            this.getter = requireNonNull(getter);
        }
    }

    // .... rest of the class ....

}


Attr attribute = Attr.valueOf("Attr1");

List<DataObject> filtered = dataObjectList.stream()
        .filter(e -> "Value_1".equals(attribute.getter.apply(e)))
        .collect(toList());

显然,缺点是您必须为每个属性添加枚举值。但优点是简单性和通过类型安全枚举而不是字符串引用属性的能力。获取有效属性列表(Attr.values())。

也很容易

设置完成后,您可以执行有趣的操作,例如将以下内容添加到enum

<T> Predicate<DataObject> matches(Predicate<T> p) {
    return e -> p.test((T)getter.apply(e));
}

然后您就可以像这样编写代码了:

Attr attribute = Attr.valueOf("Attr1");

List<DataObject> filtered = dataObjectList.stream()
        .filter(attribute.matches("Value_1"::equals))
        .collect(toList());