首页 > 解决方案 > 对象列表 - 获取对象字段的不同计数

问题描述

对于对象列表,我必须检查(某些)字段:

class Person {
   final String name;
   final int age;
   final int group;

   public Person( final String name, final int age, final int group ) {
      this.name = name;
      this.age = age;
      this.group = group;
   }

   public String getName() {
      return this.name;
   }

   public int getAge() {
      return this.age;
   }

   public int getGroup() {
      return this.group;
   }
}

public static <T> long distinctByField( final List<Person> personList, final Function<Person, T> field ) {
   return personList.stream()
         .map( field )
         .distinct().count();
}

public static void main( final String[] args ) {
   final List<Person> personList = Arrays.asList(
         new Person( "Fred", 25, 1 ),
         new Person( "Bill", 22, 1 ),
         new Person( "Fred", 27, 1 ),
         new Person( "Lisa", 25, 1 )
   );

   System.out.println( distinctByField( personList, Person::getName ) );
   System.out.println( distinctByField( personList, Person::getAge ) );
   System.out.println( distinctByField( personList, Person::getGroup ) );
}

通过流/不同/计数的结果,我可以与当前列表大小进行比较:

缺点是,我必须为每个感兴趣的领域直播。

是否可以通过一个查询(针对感兴趣的字段列表)来做到这一点?

标签: java

解决方案


可以使用反射:

public class ReflectionTest {

    class Person {
        final String name;
        final int age;
        final int group;

        public Person(final String name, final int age, final int group) {
            this.name = name;
            this.age = age;
            this.group = group;
        }

        public String getName() {
            return this.name;
        }

        public int getAge() {
            return this.age;
        }

        public int getGroup() {
            return this.group;
        }
    }

    @DisplayName("should determine distinct fields")
    @Test
    public void distinct() {
        final List<Person> personList = Arrays.asList(new Person("Fred", 25, 1),
                                                      new Person("Bill", 22, 1),
                                                      new Person("Fred", 27, 1),
                                                      new Person("Lisa", 25, 1));
        Map<String,Long> fieldCountMap = Stream.of("name", "age", "group")
                                                  .map(fieldName -> ReflectionUtils.findField(Person.class, fieldName))
                                                  .filter(Objects::nonNull)
                                                  .collect(Collectors.toMap(Field::getName, field -> personList.stream().map(person -> getField(field, person)).distinct().count()));

        assertEquals(3,fieldCountMap.get("name"));
        assertEquals(1,fieldCountMap.get("group"));
        assertEquals(3,fieldCountMap.get("age"));
    }

    //extracted into a method because field.get throws a checked exception
    Object getField(Field field, Person object) {
        try {
            return field.get(object);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

}

推荐阅读