Magic Exception thrower没有声明抛出异常

时间:2010-01-03 10:39:40

标签: java exception

我想要一个可以抛出任何Throwable的方法,包括Exception的子类。我得到了一个异常的东西,将它藏在本地的一个线程中,然后调用一个class.newInstance。该类ctor声明它抛出Exception然后获取threadlocal并抛出它。问题是它不适用于Class.newInstance()引发的两个声明的异常,即IllegalAccessExceptionInstantiationException

我猜测使用某些sun.*类的任何其他方法只是一个黑客而且不太可靠。

包装不是一种选择,因为这意味着捕手正在捕捉差异类型,这太简单而且无聊......

    static public void impossibleThrow(final Throwable throwable) {
    Null.not(throwable, "throwable");
    if (throwable instanceof RuntimeException) {
        throw (RuntimeException) throwable;
    }
    if (throwable instanceof Error) {
        throw (Error) throwable;
    }
    try {
        THROW.set((Exception) throwable);
        THROWER.newInstance();
    } catch (final InstantiationException screwed) {
        throw new Error(screwed);
    } catch (final IllegalAccessException screwed) {
        throw new Error(screwed);
    } finally {
        THROW.remove();
    }
}

private final static Class<Impossible> THROWER = Impossible.class;
private final static ThreadLocal<Exception> THROW = new ThreadLocal<Exception>();

static private class Impossible {

    @SuppressWarnings("unused")
    public Impossible() throws Exception {
        throw THROW.get();
    }
}

5 个答案:

答案 0 :(得分:3)

如果你想要一个Exception通过不期望该异常的代码冒泡,那么只需将它包装在RuntimeException中

} catch (RuntimeException e) {
   throw e;  // only wrap if needed
} catch (Exception e) {
   throw new RuntimeException("FOO went wrong", e);
}

请记住让信息提供信息。有一天,您将不得不仅根据堆栈跟踪中的信息修复错误。

答案 1 :(得分:3)

在RuntimeException中包装异常(如Thorbjørn所建议)是要走的路。但是,您通常希望保持原始excpetion的堆栈跟踪。方法如下:

  public static void rethrow(final Throwable t)
  {
     if(t instanceof RuntimeException)
        throw (RuntimeException) t;

     RuntimeException e = new RuntimeException(t);
     e.setStackTrace(t.getStackTrace());
     throw e;
  }

答案 2 :(得分:3)

来自Java Puzzlers(谜题43):

public static void impossibleThrow(Throwable t)
{
    Thread.currentThread().stop(t); // Deprecated method.
}

这本书展示了实现同样问题的其他方法,一个是你的简化版本,另一个利用泛型类型擦除来抛出任何Throwable,预计会出现错误。

答案 3 :(得分:0)

我修补了javac以删除错误,编译了impossibleThrow(),将源文件重命名为不以.java结尾的东西(强制下一次编译使用现有的.class)并使用它。

答案 4 :(得分:0)

这个问题作为调试工具有一定的效力。假设您正在处理可能失败的一些代码,并且您发现它(可能)捕获某些异常并且(可能)抛出某些异常。您怀疑未捕获到意外的异常。但是,底层代码/系统太复杂,并且错误太间歇,无法让您在调试器中单步执行。添加抛出异常而不以任何其他方式更改方法可能很有用。在这种情况下,使用RuntimeException包装异常将不起作用,因为您希望调用方法正常运行。