Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何调用未知类型的lambda_Java - Fatal编程技术网

Java 如何调用未知类型的lambda

Java 如何调用未知类型的lambda,java,Java,假设我们有一组包含方法引用的变量: public double m2(String s, int n){return n;} Runnable r = ()->{}; Consumer<String> c1 = System.out::println; BiFunction<String, Integer, Double> f2 = this::m2; 现在,我需要一个全局方法来调用任何类型的引用方法: public static Object call(Obje

假设我们有一组包含方法引用的变量:

public double m2(String s, int n){return n;}
Runnable r = ()->{};
Consumer<String> c1 = System.out::println;
BiFunction<String, Integer, Double> f2 = this::m2;
现在,我需要一个全局方法来调用任何类型的引用方法:

public static Object call(Object lambda, Object... args) {...}
Object res0 = call(r); // returns null
Object res1 = call(c1, "Hello");
Object res2 = call(f2, "Hello", 1)

如何实现这个方法?参数
lambda
的一组可能的功能类型不受限制。

您需要识别对象的类型并适当地调用/调用它。以下方法检查
可运行
可调用
方法
以及任何带有
功能接口
注释的内容。如果类型为
Method
,它将假定第一个参数是要在其上调用方法的对象

public Object callWhatever(final Object o, final Object... params) throws Exception
{
    if (o instanceof Runnable) {
        ((Runnable)o).run();
        return null;
    }

    if (o instanceof Callable) {
        return ((Callable<?>)o).call();
    }

    if (o instanceof Method) {
        return ((Method)o).invoke(params[0], Arrays.copyOfRange(params, 1, params.length));
    }

    final Method method = getMethodForFunctionalInterface(o);
    if (method != null) {
        return method.invoke(o, params);
    }

    throw new InvalidParameterException("Object of type " + o.getClass() +  " is not callable!");
}
请注意,Java允许没有
functionanterface
注释的自定义函数接口,并且该方法将检测不到该接口

现在你可以称之为:

public void test() throws Exception {
    final Runnable runnable = ()->{System.out.println("r called");};
    final Callable<Integer> callable = ()->{System.out.println("c called"); return 123456; };
    final Consumer<String> consumer = System.out::println;
    final BiFunction<String, Integer, Double> bifunction = this::m2;

    final Object test1 = callWhatever(runnable);
    final Object test2 = callWhatever(callable);
    final Object test3 = callWhatever(consumer, "Hello World");
    final Object test4 = callWhatever(bifunction, "Hello", 123);
    final Object test5 = callWhatever(this.getClass().getDeclaredMethod("m2", String.class, int.class), this, "Hello", 234);

    System.out.println(test1);
    System.out.println(test2);
    System.out.println(test3);
    System.out.println(test4);
    System.out.println(test5);
}
public void test()引发异常{
final Runnable Runnable=()->{System.out.println(“r调用”);};
final Callable Callable=()->{System.out.println(“c called”);返回123456;};
最终消费者=System.out::println;
最终双功能双功能=此::m2;
最终对象test1=callwhere(runnable);
最终对象test2=callwhater(可调用);
最终对象test3=callwhere(消费者,“Hello World”);
最终对象test4=callwhater(双函数,“Hello”,123);
最终对象test5=callwhater(this.getClass().getDeclaredMethod(“m2”,String.class,int.class),this,“Hello”,234);
System.out.println(test1);
System.out.println(test2);
System.out.println(test3);
System.out.println(test4);
System.out.println(test5);
}
输出:

r调用
c调用
你好,世界

123456

123.0
234.0

“Lambda表达式”不是一种值类型(如“object”或“int”)。它是一种表示值的方式,就像字符串文字一样

在Java中,不能编写“采用字符串文字的方法”——只能编写采用字符串的方法。您无法判断参数是否是使用文字创建的

这与lambdas完全相同-您不能编写“接受lambda”或将lambdas视为某种特殊情况的方法。一旦使用lambda创建接口实例,它的lambda特定属性就消失了,至少从Java语义的角度来看是这样

简而言之,您试图实现的并不是对lambdas的合理使用——您需要反思或重新思考您的架构

--编辑:澄清两点

  • 内部类也是如此——当您有一个对实现SomeInterface的对象的引用时,无法知道它是用内部类还是顶级类实现的。没有“内部类值类型”

  • 请注意,lambda可用于构造任何接口的值-您可以使用任意数量的方法创建一个接口,然后使用另一个接口对其进行扩展,默认实现为除一个方法外的所有方法,然后使用lambda定义最后一个方法


  • (再次编辑,感谢Sarel Foyerlicht指出了一个错误)

    注意:此答案基于答案,但有不同的方法

    在java中,Lambda表达式由

    @功能接口

    这是一条规则

    函数接口只有一个抽象方法

    因此,我们可以检查对象是否遵循该规则,然后调用该方法

    public class Example {
    
    public Example() throws Exception {
        final Runnable runnable = ()->{System.out.println("r called");};
        final Callable<Integer> callable = ()->{System.out.println("c called"); return 1000; };
        final Consumer<String> consumer = System.out::println;
        final BiFunction<String, Integer, Double> bifunction = this::m2;
        final InterfaceWithDefault inter =()->{System.out.println("print");};
    
        final Object test1 = call(runnable);
        final Object test2 = call(callable);
        final Object test3 = call(consumer, "Hello World");
        final Object test4 = call(bifunction, "Hello", 123);
        final Object test5 = call(inter);
    
        System.out.println(test1);
        System.out.println(test2);
        System.out.println(test3);
        System.out.println(test4);
        System.out.println(test5);
    }
    public static Object call(Object object, Object... param) throws Exception {
        Method method = null; 
        int publicMethods=0; 
        for (Method m:object.getClass().getDeclaredMethods()) { 
            if(Modifier.isPublic(m.getModifiers())&&!m.isDefault()){ 
              method=m; 
              publicMethods++; 
             } 
        } 
        if(publicMethods==1)
        { 
            Object returnValue = method.invoke(object, param); 
            return returnValue; 
        } 
        throw new InvalidParameterException("Object of type"+ object.getClass()+" is not callable!"); 
    }
    public double m2(String s, int n){return n;}
    public interface InterfaceWithDefault{
        public void print();
        default void defaultBar() {System.out.println("x");}
    }
    }
    
    以及输出:

    r called
    c called
    Hello World
    print
    null
    1000
    null
    123.0
    null
    
    注1:我们不需要检查抽象,因为我们的对象已经覆盖了它,但是不能有超过1个公共方法,除非其他方法是默认方法(我想不出任何情况)

    注2:它也可以只使用1个公共方法运行类

    此方法已经有了实现。它被称为。您可以
    getParameterCount()
    getParameterTypes()
    getReturnType()
    来确定如何调用此“lambda”。除了直接的反射之外,你还希望得到答案吗?也许java脚本API会是一个更好的工具:可以在脚本引擎中设置变量等等。@AJNeufeld为了使用
    方法#invoke(…)
    ,我们需要从lambda中提取方法。天真的尝试
    methodm=(Method)r导致
    异常java.lang.ClassCastException:org.df4j.reflect.FindActionTest$$Lambda$1/445884362无法强制转换为java.lang.reflect.Method
    @LouisWasserman直截了当的反射会很好,编译器将把满足函数接口定义的任何接口视为函数接口,而不管接口声明中是否存在{@code functioninterface}注释。*也许您只需要检查是否只有一个公共摘要method@SarelFoyerlicht说得好,我已经澄清了我的答案,这对于没有注释的自定义接口不起作用。如果我们遵循函数接口只允许有一个公共抽象方法的规则,公共静态对象调用(对象对象,对象…参数)抛出异常{Method Method=null;int publicMethods=0;for(方法m:object.getClass().getDeclaredMethods()){if(Modifier.isPublic(m.getModifiers())&&&!m.isDefault()){Method=m;publicMethods++;}}}if(publicMethods==1){object returnValue=Method.invoke(object,param);returnValue;}抛出新的InvalidParameterException(“类型为“+Object.getClass()+”的对象不可调用!”;}通过“lambda”我指的是可以通过上述方法之一获得的任何值:lambda表达式或方法引用。@AlexeiKaigorodov:这正是你忽略的地方。有
    public class Example {
    
    public Example() throws Exception {
        final Runnable runnable = ()->{System.out.println("r called");};
        final Callable<Integer> callable = ()->{System.out.println("c called"); return 1000; };
        final Consumer<String> consumer = System.out::println;
        final BiFunction<String, Integer, Double> bifunction = this::m2;
        final InterfaceWithDefault inter =()->{System.out.println("print");};
    
        final Object test1 = call(runnable);
        final Object test2 = call(callable);
        final Object test3 = call(consumer, "Hello World");
        final Object test4 = call(bifunction, "Hello", 123);
        final Object test5 = call(inter);
    
        System.out.println(test1);
        System.out.println(test2);
        System.out.println(test3);
        System.out.println(test4);
        System.out.println(test5);
    }
    public static Object call(Object object, Object... param) throws Exception {
        Method method = null; 
        int publicMethods=0; 
        for (Method m:object.getClass().getDeclaredMethods()) { 
            if(Modifier.isPublic(m.getModifiers())&&!m.isDefault()){ 
              method=m; 
              publicMethods++; 
             } 
        } 
        if(publicMethods==1)
        { 
            Object returnValue = method.invoke(object, param); 
            return returnValue; 
        } 
        throw new InvalidParameterException("Object of type"+ object.getClass()+" is not callable!"); 
    }
    public double m2(String s, int n){return n;}
    public interface InterfaceWithDefault{
        public void print();
        default void defaultBar() {System.out.println("x");}
    }
    }
    
    public class Main {
        public static void main(String[] args) throws Exception {
            Example exa = new Example();
        }
    }
    
    r called
    c called
    Hello World
    print
    null
    1000
    null
    123.0
    null