问题
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());
I want to filter my list of objects based on the conditions at runtime(Here condition is attr1 = "Value1_1"). My problem is that I will get the method name only in run time(It can be getAttr1() or getAttr2() or getAttr3() or any other function). I used reflection to solve this scenario.
Class<?> cls = Class.forName("com.example.java.DataObject");
Class<?> noparams[] = {};
Method method = cls.getDeclaredMethod("getAttr1", noparams);
Predicate<DataObject> first= e -> method.equals("Value1_1");
But the code will not give the required result. Please correct my code on reflection. Also please give me any alternative solutions.
回答1:
You've to actually invoke the method to get the result back using Method#invoke() method. Right now, you're just comparing the Method
object. Change that to:
Predicate<DataObject> first= e -> method.invoke(e).equals("Value1_1");
But that's really a weird way. I'm sure there can be some other way, if you can show what exactly you're trying to do.
回答2:
Are you dead-set on doing this with reflection? Reflection is often more trouble than it's worth. How about this:
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());
Obviously, the downside is that you would have to add an enum value for every attribute. But the upside is simplicity and the ability to refer to your attributes by type-safe enum rather than by strings. It will also be very easy to get a list of valid attributes (Attr.values()
).
Once you set that up, you can do fun things like adding the following to your enum
:
<T> Predicate<DataObject> matches(Predicate<T> p) {
return e -> p.test((T)getter.apply(e));
}
And then you'll be able to write your code like this:
Attr attribute = Attr.valueOf("Attr1");
List<DataObject> filtered = dataObjectList.stream()
.filter(attribute.matches("Value_1"::equals))
.collect(toList());
来源:https://stackoverflow.com/questions/29506571/predicate-with-reflection-in-java