我们可以使用函数,它为java8的可选接口取动态值



我是java 8的新手,并试图动态传递方法名称以获取值。

我有一个Request请求,它有getInput1(), getInput2()方法。我可以像这样静态地映射Optional:

void methodExecute(){ 
  Optional<Request> request = Optional.of(new Request()); 
  request.map(request::getInput1); //gives input1 value
  request.map(request::getInput2); //gives input2 value 
}

如果"getInput1""getInput2"方法名在运行时传递,我们可以动态地做同样的事情吗?

下面是我的方法。但这行不通。

@FunctionalInterface
public interface Function_WithExceptions<T, V,R, E extends Exception> {
    R apply(T t,V v) throws E;
}
public class LambdaUtil<Input1, Input2> {
    public static <Input1,Input2, R, E extends Exception> 
                            Function_WithExceptions<Input1,Input2, R,E> rethrowFunction(Function_WithExceptions<Input1,Input2, R, E> function) throws E  {
        return (t,v) -> {
            try {
                return function.apply(t,v);
            } catch (Exception exception) {
                throwActualException(exception);
                return null;
            }
        };
    }
    @SuppressWarnings("unchecked")
    private static <E extends Exception> void throwActualException(Exception exception) throws E {
        throw (E) exception;
    }
}
public Function_WithExceptions getFunction(){
        Function_WithExceptions<Request, String,Object,Exception> requestObjParamFun = (reqObj,req)->MethodUtils.invokeExactMethod(reqObj, req);
        return requestObjParamFun;
}

如果我理解正确的话,你的问题可以这样解决:

static <T> Function<Request, T> reflect(String getterName, Class<T> resultType)
           throws NoSuchMethodException, SecurityException {
    Method method = Request.class.getMethod(getterName);
    return req -> {
        try {
            return resultType.cast(method.invoke(req));
        } catch (IllegalAccessException | IllegalArgumentException
                | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    };
}

这里我们只是使用普通的反射API来获取Request类的方法,并返回调用它的函数。使用例子:

// Some test Request class
static class Request {
    public String getInput1() {return "aa";}
    public Integer getInput2() {return 1;}
}
public static void main(String[] args) throws Exception {
    Optional<Request> request = Optional.of(new Request());
    System.out.println(request.map(reflect("getInput1", String.class))); // Optional[aa]
    System.out.println(request.map(reflect("getInput2", Integer.class))); // Optional[1]
}

如果您想动态地为getter生成Function s,但不希望每次调用都诉诸于反射,您可以使用与Java语言方法引用相同的后端:

static <T> Function<Request, T> reflect(String getterName, Class<T> resultType)
            throws ReflectiveOperationException {
    MethodHandles.Lookup l=MethodHandles.lookup();
    MethodType getter=MethodType.methodType(resultType);
    MethodHandle target = l.findVirtual(Request.class, getterName, getter);
    getter=target.type();
    try {
        return (Function)LambdaMetafactory.metafactory(l, "apply",
            MethodType.methodType(Function.class),
            getter.generic(), target, getter).getTarget().invokeExact();
    } catch(Throwable ex) {
        throw new ReflectiveOperationException(ex);
    }
}

这可以使用与Tagir的解决方案相同的方式,但不会在Function调用上使用反射(通常;因为它是特定于JRE的,如果方法引用也在特定的JRE实现中使用反射,它可能会使用反射)。

但是,与反射方法一样,必须小心使用它,因为错误的使用不会在编译时发现,而是在运行时发现。

相关内容

  • 没有找到相关文章