如何将类列表作为参数传递?

Posted

技术标签:

【中文标题】如何将类列表作为参数传递?【英文标题】: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) 工作。 【参考方案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
    

【讨论】:

以上是关于如何将类列表作为参数传递?的主要内容,如果未能解决你的问题,请参考以下文章

如何将类类型作为函数参数传递

Actionscript 3:将类作为参数传递

将类对象实例作为参数从 main() 传递给另一个类对象实例

将类类型作为参数传递并针对 Kotlin 中的另一个对象检查类型

如何将列表的所有元素作为函数的参数传递而不将列表作为参数传递

如何将列表作为球拍中的参数列表传递?