Instantiate Java lambda function by name

喜夏-厌秋 提交于 2019-12-04 02:45:33
Holger

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) 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.


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.

Store the lambda instances in Map, keyed on the instance name. You can make the map globally available trough a singleton wrapper class (just watch out for synchronization issues).

class LambdaMap {

    private HashMap<String, Consumer<String>> theMap;

    private LambdaMap() {
        theMap = new HashMap<>();
    }

    private static class INSTANCE_HOLDER {
        private static LambdaMap INSTANCE = new LambdaMap();
    }

    public static LambdaMap getInstance() {
        return INSTANCE_HOLDER.INSTANCE;
    }

    public Consumer<String> put(String key, Consumer<String> value) {
        return theMap.put(key, value);
    }

    public static void Call(String aLambdaClassName, String aArg) {
        Consumer<String> func = getInstance().theMap.get(aLambdaClassName);
        if (func != null) {
            func.accept(aArg);
        }
    }

}

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

public class GlobalLambdas {

    public static void main(String[] args) {
        LambdaMap.getInstance().put("print greeting", s -> {
            System.out.println("Hello, " + s);
        });
        LambdaMap.getInstance().put("print goodbye", Host::action);

        LambdaMap.Call("print greeting", "John");
        LambdaMap.Call("print goodbye", "John");
    }
}

run:
Hello, John
Goodbye, John
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!