我们可以使用Function为java8的可选接口获取动态值

时间:2015-08-29 10:21:25

标签: java reflection lambda java-8 optional

我是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;
}

2 个答案:

答案 0 :(得分:2)

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

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]
}

答案 1 :(得分:0)

如果要为动态获取getter生成Function,但不希望每次调用都使用Reflection,则可以使用与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’s solution使用相同的方式,但不会在Function调用上使用Reflection(通常;因为它是特定于JRE的,所以它可以使用Reflection if method引用也在特定的JRE实现中使用Reflection。)

但是,与Reflection方法一样,必须谨慎使用它,因为在编译时没有发现错误的用法,而是在运行时。