【问题标题】:How to pass a list of Class as parameter?如何将类列表作为参数传递?
【发布时间】:2017-05-20 11:57:01
【问题描述】:

我试图有一个handleException 方法,它可以接受一个异常对象和一个可接受的异常类列表来检查异常是否可以接受并且可以重试。

void handleException(Exception e, String... acceptableExceptionNames)
      throws MyException {

    boolean isRetryable = false;

    for(String acceptableExceptionName: acceptableExceptionNames) {
      try {
        if (Class.forName(acceptableExceptionName).isInstance(e)) {
          isRetryable = true;
          break;
        }
      } catch (ClassNotFoundException e1) {
        continue;
      }
    }

    if (isRetryable) {
      // log retryable
    } else {
      // log error
    }

    throw new MyException(isRetryable, "Failed");
  }

我传入的参数是String... classNames,而不是Class<? extends Exception> classes,因为如果我这样做:

void handleException(
    Exception e,
    Class<? extends Exception>... acceptableExceptions)
      throws MyException {
    for (Class acceptableException : acceptableExceptions) {
        if (e instanceOf acceptableException) {}
    }
}

IDE 会抱怨unknown class acceptableException

有人知道有没有办法通过Class&lt;?&gt;?还是避免使用String classNamesClass.forName() 的更好方法?

【问题讨论】:

  • 你不能在异常中使用泛型类型!
  • 使用可变参数时,acceptableExceptions 的类型为Class[]
  • 你为什么尝试e instanceOf acceptableExceptions 与一个类数组?您演示了如何遍历数组并在另一个 sn-p 中调用 Class.isInstance 方法。
  • 而不是String数组,传递Class[] ?
  • 我只是懒得写for循环行了...所以只要找到问题。 e instanceOf classVariable 不工作,但 calssVariable.isInstance(e) 工作。

标签: java exception


【解决方案1】:

acceptableExceptions 不是Class,而是Class[]。不过,您可以保留原始设计,直接使用 Class 对象,而不是从字符串创建它们:

void handleException
        (Exception e, Class<? extends Exception>... acceptableExceptionNames)
        throws MyException {

    boolean isRetryable = false;

    for(Class<?> acceptableExceptionName: acceptableExceptionNames) {
        if (acceptableExceptionName.isInstance(e)) {
            isRetryable = true;
            break;
        }
    }

    if (isRetryable) {
        // log retryable
    } else {
        // log error
    }

    throw new MyException(isRetryable, "Failed");
}

编辑:
附带说明一下,使用 Java 8 的流可以大大缩短这段代码:

void handleException
        (Exception e, Class<? extends Exception>... acceptableExceptionNames)
        throws MyException {

    boolean isRetryable = 
        Arrays.stream(acceptableExceptionNames).anyMatch(x -> x.isInstance(e));

    if (isRetryable) {
        // log retryable
    } else {
        // log error
    }

    throw new MyException(isRetryable, "Failed");
}

【讨论】:

  • 为什么用Class&lt;?&gt;替换Class&lt;? extends Exception&gt;?您不再限制类类型。
  • @Andreas 因为Class&lt;? extends Exception&gt; 将通过acceptableExceptionNames 导致堆污染警告,尽管我不完全理解为什么会出现此警告。
  • 什么“堆污染警告”?我的 Eclipse 没有给出这样的警告。
  • @Andreas javac -d ..\bin Main.java -Xlint:unchecked -> Main.java:8: warning: [unchecked] Possible heap pollution from parameterized vararg type Class&lt;? extends Exception&gt;
  • @Andreas 好点 - 没有充分的理由,只是在我复制粘贴和编辑 OP 的代码时没有注意。已编辑和修复。
【解决方案2】:

您不想检查e 是否是Class[] 的实例,acceptableExceptions 就是这样,但如果它是其中一个 引用的类的实例通过acceptableExceptions 数组。

为此,需要对它们进行迭代,并且需要使用反射方法Class.isInstance(Object obj)。正如 javadoc 所说:

此方法是 Java 语言 instanceof 运算符的动态等效方法。

为了防止编译器警告,如果它是staticfinal,您还需要将@SafeVarargs 添加到您的方法中。否则,您需要将@SuppressWarnings("unchecked") 添加到方法及其调用者中。

@SuppressWarnings("unchecked")
void handleException(Exception e, Class<? extends Exception>... acceptableExceptions) throws MyException {
    boolean acceptable = false;
    for (Class<? extends Exception> acceptableException : acceptableExceptions)
        if (acceptableException.isInstance(e)) {
            acceptable = true;
            break;
        }
    if (acceptable) {
        // code here
    }
}

【讨论】:

  • 不幸的是,@SafeVarargs 不适用于带有可变参数的非最终实例方法。如果需要,您最终会得到@SuppressWarnings("unchecked")
  • @dhke 你是对的。我在测试中使用了 static 方法。
【解决方案3】:

在我看来,如果像这样执行简单的字符串比较会更容易:

private void handleException(Exception ex, String... acceptableException) {
    for (int x = 0; x < acceptableException.length; x++) {
        String[] exceptionClass = ex.getClass().toString().split(".");
        if (!acceptableException[x]
                .equals(exceptionClass[exceptionClass.length - 1])) {
            /* Exception Not Acceptable */
        }
    }

    /* Exception Acceptable */
}

【讨论】:

    【解决方案4】:

    使用以下检查

    for (Class<? extends Exception> exceptionClass : acceptableExceptions) {
        if (exceptionClass.isInstance(e)) {
            // it is your exception
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-02
      • 2013-11-10
      • 2013-04-21
      • 1970-01-01
      • 2022-01-02
      • 2012-10-18
      • 1970-01-01
      • 2021-10-17
      相关资源
      最近更新 更多