有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

反射投射java。朗,反思一下。方法创建一个函数接口

很难找到关于这个话题的任何线索。我能找到的只是关于将一个函数接口转换为另一个函数接口的问题,以及一些关于Java中类型转换的文章。不是我想要的

This问题是关于转换lambda → Method,我想要相反的,将^{}转换成任何函数接口,例如转换成^{}

我找到的方法是围绕Method#invoke方法创建一个lambda适配器:

    public void registerCallbacks(final Object annotated) {
        Class clazz = annotated.getClass();
        for (Method method : clazz.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Callback.class)) {
                Callback registration = method.getAnnotation(Callback.class);

                List<String> warnings = new ArrayList<>(3);

                if (!Modifier.isPublic(method.getModifiers()))
                    warnings.add(String.format("Method %s must be public", method));
                if (method.getParameterCount() != 1)
                    warnings.add(String.format("Method %s must consume only one argument", method));
                if (method.getParameterCount() == 1 && !method.getParameterTypes()[0].equals(Integer.class))
                    warnings.add(String.format("Method %s must consume %s", method, Integer.class));

                if (!warnings.isEmpty()) {
                    warnings.forEach(log::warn);
                    continue;
                }

                CALLBACKS_MAPPER.registerCallback((param) -> {
                    try {
                        method.invoke(annotated, param);
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        // Should not happen due to checks before.
                        log.warn(String.format("Could not invoke %s on %s with %s", method, annotated, param), e);
                    }
                });
                log.info("Registered {} as a callback", method);
            }
        }
    }

然而,我想避免写作

    CALLBACKS_MAPPER.registerCallback((param) -> {
        try {
            method.invoke(annotated, param);
        } catch (IllegalAccessException | InvocationTargetException e) {
            // Should not happen due to checks before.
            log.warn(String.format("Could not invoke %s on %s with %s", method, annotated, param), e);
        }
    });

支持更简单的东西,比如

    CALLBACKS_MAPPER.registerCallback(SomeApacheLib.methodToFunction(annotated, method));

➥ 那么,有没有办法将旧的Java 1.1反射库映射到新的Java 8功能接口,或者是我太愚蠢了,而上面提到的使用lambda的解决方案就可以了


共 (1) 个答案

  1. # 1 楼答案

    如果你满足于在引擎盖下使用反射,只是不喜欢try/catch周围的invoke,你可以制作一个简单的实用函数,比如:

    public static <T> Consumer<T> toConsumer(Object annotated, Method m) {
        return param -> {
            try {
                m.invoke(annotated, param);
            } catch (IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        };
    }
    

    这正是你想要的语法:

    CALLBACKS_MAPPER.registerCallback(toConsumer(annotated, method));
    

    但是如果你想完全避免反射,你可以使用LambdaMetafactory来创建一个Consumer

    static Consumer<String> toConsumer(MethodHandles.Lookup lookup, Object annotated, Method method) throws Throwable {
        MethodType consumeString = MethodType.methodType(void.class, String.class);
        MethodHandle handle = lookup.unreflect(method);
        final CallSite site = LambdaMetafactory.metafactory(lookup, "accept",
                MethodType.methodType(Consumer.class, annotated.getClass()),
                consumeString.changeParameterType(0, Object.class),
                handle,
                consumeString);
        return (Consumer<String>) site.getTarget().invoke(annotated);
    }
    

    String更改为您希望接受的回调。然后:

    CALLBACKS_MAPPER.registerCallback(toConsumer(MethodHandles.lookup(), annotated, method));
    

    当然,这里唯一正确的解决方案是重构代码,使用已知的回调接口,通常可以在该接口上调用定义的方法,而不是传递Method