使用Java Lambda从反射中收集值

使用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

我有一个数据bean,它来自一个具有基于模式的列名的大表。我需要使用Lambdas来查找
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
,6
goal*
布尔字段为
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个过滤器。一个用于检查
目标
和另一个值。