我是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实现中使用反射,它可能会使用反射)。
但是,与反射方法一样,必须小心使用它,因为错误的使用不会在编译时发现,而是在运行时发现。