使用Java Lambda从反射中收集值
我有一个数据bean,它来自一个具有基于模式的列名的大表。我需要使用Lambdas来查找使用Java Lambda从反射中收集值,java,Java,我有一个数据bean,它来自一个具有基于模式的列名的大表。我需要使用Lambdas来查找Goal*中TRUE的计数。可以通过反射调用getter public class PersonBean { //... // + with Getters/Setters private Boolean goalResearch; private Boolean goalAcademia; private Boolean goalGovt; private Boolea
Goal*
中TRUE
的计数。可以通过反射调用getter
public class PersonBean {
//...
// + with Getters/Setters
private Boolean goalResearch;
private Boolean goalAcademia;
private Boolean goalGovt;
private Boolean goalProfit;
//...
}
在一个单一的领域,我可以做反射
Boolean valueAcademia = (Boolean)(p.getClass().getDeclaredMethod("getGoalAcademia").invoke(p));
想知道如何用Streams/Lamdas快速收集这些信息。
(结果:
Goals:6
,6goal*
布尔字段为TRUE
)这行中的某些内容应该会为您提供所需的结果:
Arrays.stream(PersonBean.class.getDeclaredMethods())
.filter(declaredMethod -> declaredMethod.getName().startsWith("isGoal"))
.filter(declaredMethod -> {
try {
return (Boolean) declaredMethod.invoke(personBean);
} catch(final IllegalAccessException | InvocationTargetException exception) {
return false;
}
})
.count()
您可以使用下面的命令获得
PersonBean
type对象的目标*字段的所有true
值的计数
Arrays.stream(person.getClass().getDeclaredMethods()) //gets all methods
.filter(method -> method.getName().startsWith("getGoal")
&& method.getReturnType().equals(Boolean.class)) //gets all getters for goal* Boolean fields
.filter(getter -> {
try {
return (Boolean) getter.invoke(person); //invokes the getter
} catch (IllegalAccessException | InvocationTargetException e) {
return false;
}
})
.count();
您还可以将两个过滤器组合成一个过滤器,如下所示
Arrays.stream(person.getClass().getDeclaredMethods()) //gets all methods
.filter(method -> {
if(method.getName().startsWith("getGoal")
&& method.getReturnType().equals(Boolean.class)) {
try {
return (Boolean) method.invoke(person); //invokes the getter
} catch (IllegalAccessException | InvocationTargetException e) {
return false;
}
}
return false;
}) //gets all true values for goal* fields
.count();
我想我已经为您提出了一个解决方案:
public static void main(String[] args){
PersonBean personBean = new PersonBean(true, true, false, false);
int goalCounter = countGoals(personBean);
System.out.println(goalCounter);
}
public static Integer countGoals(PersonBean personBean){
if(personBean == null){
return 0;
}
//get all fields from parameter
Stream<Field> stream = Arrays.stream(PersonBean.class.getDeclaredFields());
return stream.filter(e -> {
if(e.getName().startsWith("goal")){
//because its private, should call this
e.setAccessible(true);
try{
return (boolean)e.get(personBean);
}catch(Exception e1){
return false;
}
}else{
return false;
}
}).mapToInt(e -> 1).sum();
}
publicstaticvoidmain(字符串[]args){
PersonBean=新PersonBean(真、真、假、假);
int goalCounter=countGoals(personBean);
系统输出打印LN(目标计数器);
}
公共静态整数countGoals(PersonBean PersonBean){
if(personBean==null){
返回0;
}
//从参数获取所有字段
Stream=Arrays.Stream(PersonBean.class.getDeclaredFields());
返回流。过滤器(e->{
if(例如getName().startsWith(“目标”)){
//因为它是私人的,应该叫它
e、 setAccessible(true);
试一试{
返回(布尔)e.get(personBean);
}捕获(异常e1){
返回false;
}
}否则{
返回false;
}
}).mapToInt(e->1.sum();
}
此外,您还可以使用更多条件改进过滤器。我只是从
PersonBean
列表中选择了名称以goal
开头的字段?我不确定我是否理解您的问题。你能提供更多的细节吗?还有getDeclaredMethods()
可以获取所有方法(甚至setter)。@Eklavya不是列表;每个PersonBean都有这些多个列。因此,对于每个PersonBean,我需要得到一个“目标*”布尔值的计数,这是真的。因此,您希望得到以Goal
开头的布尔值属性,这是真的。因此,如果6/20进球*布尔值为真,则计数为6。换句话说,我需要对我的方法进行流式处理、按名称过滤、调用和计算真值。这些字段是动态的,我不能硬编码它们。.filter(result->result)
做什么?如果你不添加.filter(result->result)
,你会得到所有的布尔值。但是,因为您只对真值感兴趣,所以需要使用@geneb的过滤器。Matthew Formosa的版本是filter&filter
,你做了filter&map&filter(result->result)。
在他的回答中,第二个过滤器可以自动过滤真实的。通常布尔属性的方法是isAttribute
。是的,昆仑的fair point,尤其是像Lombok这样的库。然而,我只是在遵循OP的示例。效果很好,我唯一做的更改是catch(异常e
)(一般情况下,没有期末考试),因为它仍然在抱怨某些错误被抛出。因此,只要尝试{..}捕获(异常e){..}
mapToInt(e->1).sum()做什么,这是否等同于.count()
?mapToInt
它就像映射
,但执行后只有整数
。和sum()
对所有整数求和。因此,结果将是一个整数
count()
这是mapToLong.sum
,它返回一个Long
,在您的情况下,使用Long
只是一种浪费。我确信您没有比Integer.MAX value
的值更多的字段。谢谢,经过测试,它正常工作。很好的解决方案,有点长,但它是有效的。@geneb。您可以将其拆分为2个过滤器。一个用于检查目标
和另一个值。