当您的方法签名不允许抛出异常时如何抛出异常?
Posted
技术标签:
【中文标题】当您的方法签名不允许抛出异常时如何抛出异常?【英文标题】:How to throw an Exception when your method signature doesn't allow to throw Exception? 【发布时间】:2012-08-10 04:37:12 【问题描述】:我有这样的方法:
public void getSomething()
...
我想在getSomething()
中抛出一个Exception
。编译器不允许我这样做,因为我的方法不允许将Exception
扔在那里。但是我需要为我的测试抛出一个 Exception
的子类(我不能抛出 Unchecked Exception
)。这显然是一个 hack,但我需要它来进行测试。我尝试了 EasyMock,但它也不允许我这样做。任何想法如何做到这一点?
谢谢, 肖恩·阮
【问题讨论】:
您正在测试一些不可能发生的事情。为什么? 我尝试使用 LogicalHandler方法一:
This post by Alexey Ragozin 描述了如何使用泛型技巧来引发未声明的检查异常。从那个帖子:
public class AnyThrow
public static void throwUnchecked(Throwable e)
AnyThrow.<RuntimeException>throwAny(e);
@SuppressWarnings("unchecked")
private static <E extends Throwable> void throwAny(Throwable e) throws E
throw (E)e;
这个技巧依赖于 throwUnchecked
向编译器“撒谎”类型 E
是 RuntimeException
并调用 throwAny
。由于throwAny
被声明为throws E
,编译器认为特定的调用可以直接抛出RuntimeException
。当然,这个技巧是通过throwAny
任意声明E
并盲目地转换为它来实现的,允许调用者决定它的参数被转换为什么 - 理智编码时的糟糕设计。在运行时,E
是 erased,没有任何意义。
正如你所说,做这样的事情是一个巨大的黑客,你应该很好地记录它的使用。
方法二:
您也可以为此使用sun.misc.Unsafe
。首先,您必须实现一个使用反射来返回该类的实例的方法:
private static Unsafe getUnsafe()
try
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
return (Unsafe)theUnsafeField.get(null);
catch (NoSuchFieldException e)
throw new RuntimeException(e);
catch (IllegalAccessException e)
throw new RuntimeException(e);
这是必要的,因为调用 Unsafe.getUnsafe()
通常会抛出 SecurityException
。一旦你有了Unsafe
的实例,你就可以使用它的可怕功能:
Unsafe unsafe = getUnsafe();
unsafe.throwException(new Exception());
致谢 this answer 在帖子 https://***.com/questions/5574241/interesting-uses-of-sun-misc-unsafe。我想我会为了完整性而提到这一点,但最好只使用上面的技巧而不是允许 Unsafe
进入你的代码。
方法三:
在有关使用 Unsafe
、@bestsss points out 的链接答案的 cmets 中,使用已弃用的方法 Thread.stop(Throwable)
是一个更简单的技巧:
Thread.currentThread().stop(new Exception());
在这种情况下,您将使用@SuppressWarnings("deprecation")
并再次非常激烈地记录。同样,我更喜欢第一个技巧,因为它的(相对)清洁度。
【讨论】:
@PaulBellora 你总是可以使用Class::newInstance()
方法,它可以抛出任何 ctor 所做的事情
@PaulBellora 为什么第一个示例在运行时没有ClassCastException
?
@Demetri (E)e
是未经检查的强制转换,这意味着如果错误,JVM 不能快速失败。类型擦除后,该方法与 private static void throwAny(Throwable e) throws Throwable throw e;
无法区分。
Unsafe
就好了
@Enerccio 直到 Java 9【参考方案2】:
Java 有两种异常,已检查和未检查。您必须声明已检查的异常,但您不必声明未检查的异常。
RuntimeException
是基本的未经检查的异常,因此您可以在不声明的情况下抛出它。
public void getSomething()
throw new RuntimeException("I don't have to be declared in the method header!");
附带说明一下,您可能不想抛出原始的 RuntimeException,而是将其子类化为更符合您需求的东西。 RuntimeException 的任何子类也将被取消选中。
【讨论】:
很抱歉不清楚。我需要抛出 java.lang.Exception 的子类(检查异常)。 @SeanNguyen RuntimeException 是异常的子类。这只是 Java 中的一种特殊情况,您不需要声明它会被抛出。 对不起,又不是很清楚。我需要抛出作为异常子类的已检查异常。我不能抛出 RuntimeException。 @SeanNguyen:请告诉我们为什么需要抛出一个检查异常。【参考方案3】:我不知道你想做什么。您可以在方法中抛出未经检查的异常,然后使用 JUnit 进行测试,如下面的示例所示。
public void getSomething()
throw new RuntimeException();
JUnit 4 测试示例:
@Test
public void testGetSomething()
try
getSomething();
fail("Expecting RuntimeException!");
catch (Exception e)
Logger.getLogger("test").info("Exception was caught: " + e.getClass());
【讨论】:
以上是关于当您的方法签名不允许抛出异常时如何抛出异常?的主要内容,如果未能解决你的问题,请参考以下文章