如何将类列表作为参数传递?
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<?>
?还是避免使用String classNames
和Class.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<?>
替换Class<? extends Exception>
?您不再限制类类型。
@Andreas 因为Class<? extends Exception>
将通过acceptableExceptionNames
导致堆污染警告,尽管我不完全理解为什么会出现此警告。
什么“堆污染警告”?我的 Eclipse 没有给出这样的警告。
@Andreas javac -d ..\bin Main.java -Xlint:unchecked
-> Main.java:8: warning: [unchecked] Possible heap pollution from parameterized vararg type Class<? extends Exception>
@Andreas 好点 - 没有充分的理由,只是在我复制粘贴和编辑 OP 的代码时没有注意。已编辑和修复。【参考方案2】:
您不想检查e
是否是Class[]
的实例,acceptableExceptions
就是这样,但如果它是其中一个 引用的类的实例通过acceptableExceptions
数组。
为此,需要对它们进行迭代,并且需要使用反射方法Class.isInstance(Object obj)
。正如 javadoc 所说:
此方法是 Java 语言
instanceof
运算符的动态等效方法。
为了防止编译器警告,如果它是static
或final
,您还需要将@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
【讨论】:
以上是关于如何将类列表作为参数传递?的主要内容,如果未能解决你的问题,请参考以下文章
将类对象实例作为参数从 main() 传递给另一个类对象实例
将类类型作为参数传递并针对 Kotlin 中的另一个对象检查类型