Java 如何通过反射从静态方法获取谓词?

Java 如何通过反射从静态方法获取谓词?,java,reflection,predicate,Java,Reflection,Predicate,给定一个由静态谓词方法组成的类,我希望通过反射访问它们,并将它们转换为谓词类型 public class MyPredicates { public static boolean isNull(Object obj) { return obj == null; } public static boolean hasNegativeHashcode(Object obj) { return obj.hashCode() < 0;

给定一个由静态谓词方法组成的类,我希望通过反射访问它们,并将它们转换为
谓词
类型

public class MyPredicates {
    public static boolean isNull(Object obj) {
        return obj == null;
    }

    public static boolean hasNegativeHashcode(Object obj) {
        return obj.hashCode() < 0;
    }
}
公共类MyPredicates{
公共静态布尔值isNull(对象obj){
返回obj==null;
}
公共静态布尔hasNegativeHashcode(对象obj){
返回obj.hashCode()<0;
}
}
通常,我会编写以下代码来获取谓词:

Predicate<Object> isNull = MyPredicates::isNull;
谓词isNull=MyPredicates::isNull;
然而,我不知道如何使用反射来实现这一点。我的意图是为这些方法创建一个注释,并通过反射获得它们,从而为我的框架创建一个可用谓词列表

我想到了三种可能的方法,对我来说没有一种是好的

  • 我可以像
    Method
    那样保留它,调用
    invoke()
    并将返回的
    对象转换为
    布尔值。然而,这将很难阅读,这意味着我无法在运行时检查类型
  • 我可以将反射调用包装为
    谓词
    ,但这将涉及额外的开销
  • 我可以让用户分别注册每个方法(添加/删除许多方法时很难维护)
  • 在任何情况下,我担心直接使用反射会增加更多的开销并降低程序的速度

    因此,我的问题是:

  • 我可以直接通过反射得到
    谓词吗
  • 如果不是,在拥有可用的API(例如通过使用
    谓词
    )的情况下,访问这些方法而不增加太多开销的合适方式是什么

  • TL;DR:直接从静态方法返回
    谓词
    ,并将其存储以备将来使用(可能存储在方法名称为键的映射中),以消除反射访问的速度瓶颈

    public static Predicate<Object> isNull() {
        return obj -> obj == null;
    }
    
    翻译为

    list.filter(indy(MH(metaFactory), MH(invokeVirtual Predicate.apply), MH(invokeVirtual String.isEmpty))()))
    
    这意味着
    谓词在运行时不存在,除非您在代码中编写它。可能有一种通过反射API获取它的方便方法,但据我所知,没有。你也许能用英语写一些类似的东西;然而,我认为这会给代码增加不必要的复杂性

    以下是实现预期行为的4种不同方法的基准,包括问题中提到的方法:

    Benchmark                                     Mode  Cnt    Score    Error   Units
    MyBenchmark.testNormal                       thrpt   30  362.782 ± 13.521  ops/us
    MyBenchmark.testReflectionInvoke             thrpt   30   60.440 ±  1.394  ops/us
    MyBenchmark.testReflectionWrappedPredicate   thrpt   30   62.948 ±  0.846  ops/us
    MyBenchmark.testReflectionReturnedPredicate  thrpt   30  381.780 ±  5.265  ops/us
    
  • testNormal通过
    运算符访问谓词
  • testReflectionInvoke直接使用
    invoke()
    方法
  • testReflectionWrappedPredicate
    invoke()
    方法包装为
    Precicate
  • testReflectionReturnedPredicate使用返回
    谓词的方法,因此反射只被调用一次
  • 在本例中,谓词是缓存的,因为我们不测试获取谓词的速度,而是假设它只执行一次

    从结果中可以看出,反射比正常访问谓词慢6倍。因此,在我看来,最干净/最可维护的方法是让不带参数的方法返回
    谓词
    类型
    ,而不是
    布尔

    public static Predicate<Object> isNull() {
        return obj -> obj == null;
    }
    
    公共静态谓词isNull(){
    返回obj->obj==null;
    }
    

    基准测试使用了3个fork、4个预热迭代和10个迭代

    以下是我用于测试的代码,如果您想自己运行基准测试(使用JMH框架进行基准测试):

    公共类MyBenchmark{
    公共静态谓词normal=MyBenchmark::isNull;
    公共静态方法反射波;
    公共静态谓词reflectionWrappedPredicate;
    公共静态谓词reflectionReturnedPredicate;
    静止的{
    试一试{
    方法m1=MyBenchmark.class.getMethod(“isNull”,Object.class);
    反射率为m1;
    reflectionWrappedPredicate=a->{
    试一试{
    返回值(布尔值)m1.invoke(null,a);
    }
    catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException ex){
    返回false;
    }
    };
    方法m2=MyBenchmark.class.getMethod(“isNull”);
    reflectionReturnedPredicate=(谓词)m2.invoke(null);
    }
    catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException ex){
    例如printStackTrace();
    };
    }
    @基准
    @输出时间单位(时间单位,微秒)
    公共布尔testNormal(){
    谓词p=正常;
    返回p.test(this)| p.test(null);
    }
    @基准
    @输出时间单位(时间单位,微秒)
    公共布尔testReflectionInvoke(){
    试一试{
    方法m=反射波;
    return(boolean)m.invoke(null,this)|(boolean)m.invoke(null,(Object)null);
    }
    catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException ex){
    例如printStackTrace();
    返回false;
    }
    }
    @基准
    @输出时间单位(时间单位,微秒)
    公共布尔testReflectionWrappedPredicate(){
    谓词p=reflectionWrappedPredicate;
    返回p.test(this)| p.test(null);
    }
    @基准
    @输出时间单位(时间单位,微秒)
    公共布尔testReflectionReturnedPredicate(){
    谓词p=reflectionReturnedPredicate;
    返回p.test(this)| p.test(null);
    }
    公共静态布尔值isNull(对象obj){
    返回obj==null;
    }
    公共静态谓词isNull(){
    返回obj->obj==null;
    }
    }
    
    我不明白你为什么需要反思。难道您的注释处理器不知道什么
    public static Predicate<Object> isNull() {
        return obj -> obj == null;
    }
    
    public class MyBenchmark {
        public static Predicate<Object> normal = MyBenchmark::isNull;
        public static Method reflectionInvoke;
        public static Predicate<Object> reflectionWrappedPredicate;
        public static Predicate<Object> reflectionReturnedPredicate;
    
        static {
            try {
                Method m1 = MyBenchmark.class.getMethod("isNull", Object.class);
                reflectionInvoke = m1;
                reflectionWrappedPredicate = a -> {
                    try {
                        return (boolean)m1.invoke(null, a);
                    }
                    catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
                        return false;
                    }
                };
    
                Method m2 = MyBenchmark.class.getMethod("isNull");
                reflectionReturnedPredicate = (Predicate)m2.invoke(null);
            }
            catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException ex) {
                ex.printStackTrace();
            };
        }
    
        @Benchmark
        @OutputTimeUnit(TimeUnit.MICROSECONDS)
        public boolean testNormal() {
            Predicate<Object> p = normal;
            return p.test(this) | p.test(null);
        }
    
        @Benchmark
        @OutputTimeUnit(TimeUnit.MICROSECONDS)
        public boolean testReflectionInvoke() {
            try {
                Method m = reflectionInvoke;
                return (boolean)m.invoke(null, this) | (boolean)m.invoke(null, (Object)null);
            }
            catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException ex) {
                ex.printStackTrace();
                return false;
            }
        }
    
        @Benchmark
        @OutputTimeUnit(TimeUnit.MICROSECONDS)
        public boolean testReflectionWrappedPredicate() {
            Predicate<Object> p = reflectionWrappedPredicate;
            return p.test(this) | p.test(null);
        }
    
        @Benchmark
        @OutputTimeUnit(TimeUnit.MICROSECONDS)
        public boolean testReflectionReturnedPredicate() {
            Predicate<Object> p = reflectionReturnedPredicate;
            return p.test(this) | p.test(null);
        }
    
        public static boolean isNull(Object obj) {
            return obj == null;
        }
    
        public static Predicate<Object> isNull() {
            return obj -> obj == null;
        }
    }