有 Java 编程相关的问题?

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

java在运行时收到谓词函数的名称时,如何将一个函数作为谓词传递给另一个函数?

我收到了在运行时用作biPredicate的函数名。我想通过这个双向预测和评估,基本上过滤得到结果。 下面是我的实用程序,它定义了biPredicates。我尝试使用MethodHandle和Lambda函数。当我使用

new FilterUtility().execute("genericFilter");

I get java.lang.AbstractMethodError

public class FilterUtility {

public void execute(String filterName) throws Throwable {
    ActualBean beanObject = ActualBean.builder().param1("true").param2("false").build();

    MethodType methodType = MethodType.methodType(boolean.class, Object.class, Object.class);
    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodHandle handle = lookup.findStatic(FilterUtility.class, filterName, methodType);
    BiPredicate<Object, Object> f = (BiPredicate<Object, Object>) LambdaMetafactory.metafactory(lookup,
            "test",
            MethodType.methodType(BiPredicate.class),
            methodType.generic(),
            handle,
            methodType)
            .getTarget()
            .invokeExact();

    resolve(beanObject, new HashMap<>(), f);
}

public static <SourceObject, TemplateObject> Map<String, String> resolve(SourceObject src,
        TemplateObject template,
        BiPredicate<SourceObject, TemplateObject> p) {
    if (p.test(src, template))
        return new HashMap<>();

    return null;
}

public static <SourceObject, TemplateObject> boolean genericFilter(SourceObject x, TemplateObject y) {
    ObjectMapper ob = new ObjectMapper();
    Map<String, Object> source = ob.convertValue(x, Map.class);
    Map<String, Object> template = ob.convertValue(y, Map.class);

    for (Map.Entry<String, Object> entry : template.entrySet()) {
        if (!source.get(entry.getKey()).equals(entry.getValue()))
            return false;
    }
    return true;
}
}

当我将execute的实现更改为following时,不会出现异常

public void execute(String filterName) throws Throwable {
    ActualBean beanObject = ActualBean.builder().param1("true").param2("false").build();
    resolve(beanObject, new HashMap<>(), FilterUtility::genericFilter); }

这让我相信,我试图找到具有名称的函数并将其作为双预测发送的方式有问题


共 (1) 个答案

  1. # 1 楼答案

    您正在调用方法methodType.generic(),该方法将用java.lang.Object替换所有参数类型和返回类型,包括基元类型。因此,您正在将目标方法的签名(Object,Object)->boolean转换为(Object,Object)->Object,有效地创建了一个带有方法Object test(Object,Object)的类,该方法将调用您的目标方法并将结果框起来

    lambda元工厂不会检查此类类型不匹配。因此,当您试图在生成的类上调用BiPredicate的方法boolean test(Object,Object)时,将抛出一个错误

    正确的方法是methodType.erase(),它将用java.lang.Object替换所有引用类型,但保持原语类型不变。不过,在这种特定情况下,根本不需要转换方法类型,因为目标方法的类型已经是(Object,Object)->boolean,所以用methodType替换methodType.generic()也可以