通过名称实例化Java lambda函数 [英] Instantiate Java lambda function by name

查看:273
本文介绍了通过名称实例化Java lambda函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在Java 8中创建一个lambda函数,获取它的类名,然后稍后从其类名再次实例化该函数.

I would like to create a lambda function in Java 8, get it's classname and then later instantiate the function again from its classname.

这是我尝试的方法:

import java.util.function.Consumer;

public class SimpleLambda
{
    public static void call(String aLambdaClassName, String aArg) throws Exception
    {
        Class<Consumer<String>> lClass = (Class<Consumer<String>>) Class.forName(aLambdaClassName);
        Consumer<String> newlamba = lClass.newInstance();
        newlamba.accept(aArg);
    }

    public static void main(String[] args) throws Exception
    {
        {
            // Attempt with a static method as lambda
            Consumer<String> lambda = Host::action;
            String classname = lambda.getClass().getName();
            call(classname, "Hello world");
        }

        {
            // Attempt with a locally defined lambda
            Consumer<String> lambda = (s) -> { System.out.println(s); };
            String classname = lambda.getClass().getName();
            call(classname, "Hello world");
        }
    }
}

class Host {
    public static void action(String aMessage) {
        System.out.println(aMessage);
    }
}

但是,使用此代码(在这两种变体中,都使用了静态方法引用并使用了本地声明的lambda),我得到了一个异常:

However, with this code (in both variants, using the static method reference and using the locally declared lambda), I get an exception:

Exception in thread "main" java.lang.ClassNotFoundException: mypackage.SimpleLambda$$Lambda$1/471910020
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at mypackage.SimpleLambda.main(SimpleLambda.java:12)

我希望至少可以重新实例化静态方法引用……不,显然不是.

I would have expected that at I can at least re-instantiate the static method reference... nope, apparently not.

我在Groovy Closures中使用了类似的方法,效果很好.因此,我对Java 8 lambda所做的事情有问题吗,还是无法通过名称实例化lambda?我在网上发现了一些提示,可以对lambda进行序列化,因此我希望也可以通过名称实例化它们.

I have been using a similar approach with Groovy Closures and that worked nicely. So am I just doing something wrong with the Java 8 lambdas, or is it not possible to instantiate lambdas by name? I found some hints on the net that lambdas can be (de)serialized, so I would expect it should also be possible to instantiate them by name.

推荐答案

好,Oracle的JRE/OpenJDK的一个特殊属性是使用匿名类",而这些匿名类根本无法通过名称访问.但是即使没有这个,也没有理由应该起作用:

Well, it is a special property of Oracle’s JRE/OpenJDK to use "anonymous classes", which can’t be accessed by name at all. But even without this, there is no reason why this ought to work:

  • Class.forName(String)尝试通过呼叫者的ClassLoader解析课程.因此,即使lambda表达式是使用普通类实现的,但如果通过不同的ClassLoader
  • 加载,也无法访问
  • Class.newInstance()仅在存在public无参数构造函数的情况下有效.您不能假定没有no-arg构造函数,也不能假设它是public
  • 认为整个函数的逻辑必须位于一个类中的假设是错误的.一个反例是java.lang.reflect.Proxy,它生成委托给InvocationHandlerinterface实现.尝试通过其类名重新实例化此类代理将会失败,因为您需要将实际的InvocationHandler实例传递给代理的构造函数.原则上,JRE特定的lambda表达式实现可以使用类似的模式
  • Class.forName(String) tries to resolve the class via the caller’s ClassLoader. So even if lambda expressions were implemented using ordinary classes, there were not accessible if loaded via a different ClassLoader
  • Class.newInstance() only works if there is a public no-arg constructor. You can’t assume that there is a no-arg constructor nor that it is public
  • The assumption that the entire function’s logic has to reside in a single class is wrong. A counter-example would be java.lang.reflect.Proxy which generates interface implementations delegating to an InvocationHandler. Trying to re-instantiate such a proxy via its class name would fail, because you need the to pass the actual InvocationHandler instance to the proxy’s constructor. In principle, the JRE specific lambda expression implementation could use a similar pattern

考虑到以上几点,应该明确地说,您不能说它通常适用于内部类.为此,您必须满足许多约束条件.

Considering the points above, it should be clear that you can’t say that it worked with inner classes in general. There are a lot of constraints you have to fulfill for that.

关于序列化,它适用于可序列化的lambda表达式,因为持久性形式与运行时实现类完全分离,如中所述答案.因此,生成的类的名称不包含在序列化形式中,并且反序列化端可能具有完全不同的运行时实现.

Regarding Serialization, it works for serializable lambda expressions, because the persistent form is completely detached from the runtime implementation class, as described in this answer. So the name of the generated class is not contained in the serialized form and the deserializing end could have an entirely different runtime implementation.

这篇关于通过名称实例化Java lambda函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆