很难找到该主题的任何线索。我只能找到有关将一个功能接口转换为另一个功能接口的问题,以及一些有关Java中类型转换的文章。不是我要找的东西。
这个问题是关于转换的,lambda →Method
而我想相反地转换Method
为任何功能接口,例如to
Consumer
。
我发现的方法是围绕该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的解决方案就可以了?
如果您对在幕后使用反射感到满意,只是不喜欢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
s。
和往常一样,我在浏览JDK8源代码时发现了非常有趣的代码: 问题是:如何可能是的实例?因为它们处于不同的层级。 我做了类似的代码片段来测试转换:
MainActivity.java 对不起,我的英语很差。
问题内容: 所以这工作: 但这不是: 总而言之,我得到了第一部分(拳击),但是我发现第二部分不起作用是非常不直观的。是否有特定的原因(除了String从Object继承而int不从Object继承)? 编辑: 为了完善我的问题,这也可以: 但是,以下内容却没有: 令人惊讶的是,您遇到了与String相同的问题: 在最后一行产生类强制转换异常。仍然有效: 问题答案: 我刚刚找到了我正在寻找自己的答案
问题内容: 我实现了以下代码: 当单独编译时,这两行都可以正常编译,但是使用给出运行时错误 。 为什么它们编译良好,但会给出运行时错误? 问题答案: type变量可以像在case类中那样存储对类型或其子类型的对象的引用。 因此,可能会有类似以下的代码: 变量是类型的,因此它只能访问该类的API,而不能访问在类B中添加的方法,即它所指向的对象。但是有时我们希望能够访问那些方法,因此应该可以以某种方式
我一直收到JAXB转换错误。 在这一点上我不确定该纠正什么。 解组: 错误消息: 不能将条目强制转换为javax.xml.bind.JaxbElement 问题更新 @XmlAccessorType(XmlAccessStype.Field)公共类条目{ XML: