如何按类型动态创建通用lambda实现?

Wi-*_*-Al 1 java generics reflection predicate java-8

例如,我有课

public class Human {

  private String name;

  ...
}
Run Code Online (Sandbox Code Playgroud)

我想实现这样的事情:

(1)

List<Human> humans =  initHumans();
Equals<Human> humanEquals = new Equals<>();
Predicate<Human> filter = humanEquals.filter("name", "John");
List<Human> filteredHumans = humans
    .stream()
    .filter(filter)
    .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

等于:

public class Equals<T> extends AbstractPredicate<T> {

  public java.util.function.Predicate<T> filter(String fieldName, String fieldValue) {
    ....
  }  
}
Run Code Online (Sandbox Code Playgroud)

是否提供了(1)行为的有效工具过滤方法?

我想回复Predicate这样的:

Predicate<Human> predicate = human -> human.getName().equals("John");
Run Code Online (Sandbox Code Playgroud)

同样应该适用于其他类:

Predicate<Car> filter = humanEquals.filter("color", "red");
//like this:
Predicate<Car> predicate= human -> human.getColor().equals("red");
Run Code Online (Sandbox Code Playgroud)

And*_*lko 5

是的,这可以通过反思来实现:

public static <T> Predicate<T> filter(Class<T> clazz, String fieldName, Object fieldValue) {
    // 1
    return (T instance) -> {
        try {
            final Field field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);

            return fieldValue.equals(field.get(instance));
        } catch (NoSuchFieldException | IllegalAccessException e) {
            // 2
        }
        return false;
    };
}
Run Code Online (Sandbox Code Playgroud)
  • 我创建了一个方法,static因为我不知道它AbstractPredicate是什么以及为什么需要创建实用程序类的实例.
  • 我直接从字段中获取值而不使用getter - 我们应该遵循哪种命名约定?(可能会有所改进)

用途是:

final Predicate<Human> filter = Equals.filter(Human.class, "name", "John");

System.out.println(filter.test(new Human("John")));     // true
System.out.println(filter.test(new Human("Andrew")));   // false
Run Code Online (Sandbox Code Playgroud)

我们还需要考虑一些问题 - 验证参数(1),处理异常(2).


另一个选项可以是使用a Function<T, E>来提供对getter的引用:

public static <T, E> Predicate<T> filter(Function<T, E> supplier, E value) {
    return (T instance) -> supplier.apply(instance).equals(value);
}
Run Code Online (Sandbox Code Playgroud)

使用示例:

final Predicate<Human> predicate = Equals.filter(Human::getName, "John");

System.out.println(predicate.test(new Human("John")));    // true
System.out.println(predicate.test(new Human("Andrew")));  // false
Run Code Online (Sandbox Code Playgroud)

  • 我想如果问题是字面意思,想要将属性称为String,则没有别的办法.但是,这里有一些XY问题:我怀疑Wi-Al会满足于像`Equals.filter(Human :: getName,"John")`这样的东西. (4认同)