Java 是否有访问getDeclaredMethod的非异常方法?

Java 是否有访问getDeclaredMethod的非异常方法?,java,reflection,Java,Reflection,我有两个可能需要调用方法的对象,我不知道它属于哪一个。目前,我的基本工作流程如下: Method method = null; Target target = null; try { method = first.getClass().getDeclaredMethod(methodName, typeParams); target = first; } catch(NoSuchMethodException e) { try { method = se

我有两个可能需要调用方法的对象,我不知道它属于哪一个。目前,我的基本工作流程如下:

Method method = null;
Target target = null;
try {
    method = first.getClass().getDeclaredMethod(methodName, typeParams);
    target = first;
} catch(NoSuchMethodException e) { 
    try {
        method = second.getClass().getDeclaredMethod(methodName, typeParams);
        target = second;
    } catch(NoSuchMethodException e1) {
        // they sent us a bad command, return 404-esque response
    }
}
method.invoke(target, arguments);
我真的希望避免所有这样的异常处理,因为没有方法不是真正的异常,而是一种期望。理想是

if(first.getClass().hasDeclaredMethod(methodName, typeParams)) {
    return first.getClass().getDeclaredMethod(methodName, typeParams).invoke(first, arguments); 
}
if(second.getClass().hasDeclaredMethod(methodName, typeParams)) {
    return second.getClass().getDeclaredMethod(methodName, typeParams).invoke(second, arguments); 
}
// they sent us a bad command, return 404-esque response

有哪些选项可以通过这种方式减少对异常的依赖?我不希望编写“包装器方法”,因为这些方法可能会很麻烦,并且很难判断何时发生错误。

我会选择自定义帮助器方法。这样做应该可以:

static Optional<Object> invokeMethodIfPresent(Object target, String methodName, 
       Class<?>[] typeParams, Object[] arguments) {
    try {
        Method m = target.getClass().getDeclaredMethod(methodName, typeParams);
        return Optional.of(m.invoke(target, arguments));
    } catch (NoSuchMethodException e) {
        return Optional.empty();
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

或者使用多个对象:

当您不想捕获异常时,必须实现搜索,即

public static Optional<Method> getMethod(Class<?> decl, String name, Class<?>... arg) {
    return Arrays.stream(decl.getDeclaredMethods())
        .filter(m -> name.equals(m.getName()) && Arrays.equals(m.getParameterTypes(), arg))
        .findAny();
}
public静态可选getMethod(类decl、字符串名称、类…arg){
返回Arrays.stream(decl.getDeclaredMethods())
.filter(m->name.equals(m.getName())&数组.equals(m.getParameterTypes(),arg))
.findAny();
}
你可以像这样使用它

Optional<Method> m = getMethod(target.getClass(), methodName, typeParams);
if(!m.isPresent()) {
    target = second;
    m = getMethod(target.getClass(), methodName, typeParams);
}
if(m.isPresent()) try {
    m.get().invoke(target, args);
}
catch (IllegalAccessException|InvocationTargetException ex) {
    …
}
可选m=getMethod(target.getClass(),methodName,typeParams);
如果(!m.isPresent()){
目标=秒;
m=getMethod(target.getClass(),methodName,typeParams);
}
如果(m.isPresent())尝试{
m、 get().invoke(目标,参数);
}
捕获(IllegalAccessException | InvocationTargetException ex){
…
}
尽管使用可选项的其他方式也是可能的

您可能会说“等待……但这会在所有声明的方法中进行线性搜索”,但是,没有人承诺过
getDeclaredMethod(String,Class…)
会比线性搜索做得更好,事实上,在广泛使用的参考实现中,它不会。它执行的搜索与上面显示的逻辑相同,除了在没有找到匹配项的情况下在结尾抛出异常之外


即使这样做了,例如散列查找,创建新异常的成本也可能超过通过有限数量的声明方法进行线性搜索的成本

您可以列出所有declaredMethods并测试它们,以检查其中一个是否与您期望的方法签名相对应。如果您有Java9,可能方法句柄会有所帮助。与反射类似,但检查只在创建时发生一次。如果这没有帮助,那就没有别的了。反射天生容易出错,因此到处都可能出现异常。@GhostCat是java.lang.invoke,旨在成为java.lang.reflect的现代替代品?我认为@kumesana是我需要去的地方。我只是在第一个上构建了一个可接受方法的缓存,然后在第二个上构建了一个可接受方法的缓存。当我看到它如何运行时,我将分享我的解决方案。如果你想用一些基本代码来回答这个问题,我很乐意给你适当的评价。句柄是一种提供Java反射而不会对性能造成永久影响的方法。如上所述:句柄在创建时检查一次,但使用方法对象会导致每次使用它时都进行相同的检查。
Optional<Method> m = getMethod(target.getClass(), methodName, typeParams);
if(!m.isPresent()) {
    target = second;
    m = getMethod(target.getClass(), methodName, typeParams);
}
if(m.isPresent()) try {
    m.get().invoke(target, args);
}
catch (IllegalAccessException|InvocationTargetException ex) {
    …
}