我是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;
}
答案 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方法一样,必须谨慎使用它,因为在编译时没有发现错误的用法,而是在运行时。