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");
但代码不会提供所需的结果。请在反思中更正我的代码。另外请给我任何替代解决方案。
答案 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());