重新抛出已检查的异常

发布于 2024-10-09 17:37:46 字数 273 浏览 0 评论 0原文

public void foo() {
 begin();
 try {
  ...
  commit();
 } catch (Exception e) {
  rollback();
  throw e;
 }
}

在上面的示例中,出现错误是因为 foo 没有 throws Exception。添加这一点也不会使该方法的可用性变得很好。

最好的方法是什么?如果发生错误而没有真正“处理”错误,您该如何处理?

public void foo() {
 begin();
 try {
  ...
  commit();
 } catch (Exception e) {
  rollback();
  throw e;
 }
}

In the sample above, there is an error because foo has no throws Exception. Adding that wouldn't make do the method's usability a lot of good either.

What's the best way to do this? How do you do something if an error occurs without really "handling" the error?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

甜是你 2024-10-16 17:37:46

从 Java 8 开始,

/**
 * Cast a CheckedException as an unchecked one.
 *
 * @param throwable to cast
 * @param <T> the type of the Throwable
 * @return this method will never return a Throwable instance, it will just throw it.
 * @throws T the throwable as an unchecked throwable
 */
@SuppressWarnings("unchecked")
public static <T extends Throwable> RuntimeException rethrow(Throwable throwable) throws T {
    throw (T) throwable; // rely on vacuous cast
}

我们可以重新抛出检查异常,但只能通过避免编译器检查异常验证。

public void foo() throws MyCheckedException {
 begin();
 try {
  ...
  commit();
 } catch (Exception e) {
  rollback();
  // same as throwing an exception without the compiler knowing.
  Thread.currentThread().stop(e); 
 }
}

在使用 stop() 之前,您应该阅读 http:// download.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

Thread.currentThread().stop(e) .. 在行为上与 Java 的 throw 操作相同,但绕过了编译器的尝试,以保证调用方法已声明它可能抛出的所有已检查异常:

Since Java 8 we use

/**
 * Cast a CheckedException as an unchecked one.
 *
 * @param throwable to cast
 * @param <T> the type of the Throwable
 * @return this method will never return a Throwable instance, it will just throw it.
 * @throws T the throwable as an unchecked throwable
 */
@SuppressWarnings("unchecked")
public static <T extends Throwable> RuntimeException rethrow(Throwable throwable) throws T {
    throw (T) throwable; // rely on vacuous cast
}

You can rethrow a checked exception, but only by avoiding the compilers checked exception validation.

public void foo() throws MyCheckedException {
 begin();
 try {
  ...
  commit();
 } catch (Exception e) {
  rollback();
  // same as throwing an exception without the compiler knowing.
  Thread.currentThread().stop(e); 
 }
}

Before you use stop() you should read http://download.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

Thread.currentThread().stop(e) .. is behaviorally identical to Java's throw operation, but circumvents the compiler's attempts to guarantee that the calling method has declared all of the checked exceptions that it may throw:

强辩 2024-10-16 17:37:46

我至少会想到两种方法,通常会组合,具体取决于您希望 foo 执行的操作:

1. 仅捕获并重新抛出相关异常

只有主流程中的代码可能会抛出如此多的异常(可能主要是 SqlException)。因此,只能捕获并重新抛出它们,并声明您正在这样做。更重要的是,仅重新抛出那些您实际上没有处理的代码(在简化的示例代码中,您没有处理任何代码,但您的现实生活代码可能更微妙)。

请注意,某些异常可能是运行时异常,因此您可能希望将其与以下异常结合起来。

2.根本不要捕获异常

像这样:

// Signature changes to include any exceptions that really can be thrown
public void foo() throws XYZException, ABCException {
 // A flag indicating that the commit succeeded
 boolean done = false;

 begin();
 try {
  // Don't have any `return` statements in here (or if you do,
  // set `done` to `true` first)

  ...
  commit();
  done = true; // Commit didn't throw an exception, we're done
 } finally {
  // finally clause always happens regardless
  if (!done) {
    // We must be processing an exception; rollback
    try {
      rollback();
    } catch (Exception e) {
      // quash it (e.g., leave this block empty), we don't want
      // to mask the real exception by throwing a different one
    }
  }
 }
}

当然,您的签名需要包含主流中可能引发的任何异常,但这就是您想要做的,如果我理解正确的话。

同样,您很可能结合这两种方法,因为您可能想要处理一些异常而不是其他异常。

At least two approaches come to mind, which are usually going to be combined depending on what you want foo to do:

1. Catch and rethrow only the relevant exceptions

There are only so many exceptions the code in your main flow can throw (probably mostly SqlExceptions). So only catch and rethrow those, and declare that you're doing so. More to the point, rethrow only the ones you're not actually handling (in your simplified sample code, you're not handling any, but your real life code is probably more subtle).

Mind you, some of the exceptions may be runtime exceptions, and so you may want to combine this with the below.

2. Don't catch the exception at all

Like this:

// Signature changes to include any exceptions that really can be thrown
public void foo() throws XYZException, ABCException {
 // A flag indicating that the commit succeeded
 boolean done = false;

 begin();
 try {
  // Don't have any `return` statements in here (or if you do,
  // set `done` to `true` first)

  ...
  commit();
  done = true; // Commit didn't throw an exception, we're done
 } finally {
  // finally clause always happens regardless
  if (!done) {
    // We must be processing an exception; rollback
    try {
      rollback();
    } catch (Exception e) {
      // quash it (e.g., leave this block empty), we don't want
      // to mask the real exception by throwing a different one
    }
  }
 }
}

Naturally your signature needs to include any exceptions that may be thrown in the main flow, but that's what you're trying to do, if I'm understanding you correctly.

Again, you may well combine these two approaches, because you may want to handle some exceptions and not others.

挽清梦 2024-10-16 17:37:46

用一些未检查的 RuntimeException 包裹它。

Wrap it with some RuntimeException which is unchecked.

陌伤ぢ 2024-10-16 17:37:46

添加它也不会使该方法的可用性变得很好。

。它将擅长记录文档,并且调用者也会小心处理它。

另请参阅

Adding that wouldn't make do the method's usability a lot of good either.

No. It will be good at documentation, also caller will take care handling it.

Also See

只为守护你 2024-10-16 17:37:46

我想说,在这种情况下回滚就是适当地处理异常。这是少数可以合法接球并重新投掷的情况之一。

我不会考虑处理简单地捕获和记录异常。在这种情况下,我宁愿看到已检查的异常添加到方法签名中并让它冒泡,而不是重新抛出。

I'd say that in this case rolling back is handling the exception appropriately. It's one of the few cases where it's legitimate to catch and re-throw.

Simply catching and logging an exception is not what I would consider handling. Rather than rethrowing, in that case I'd rather see checked exceptions added to the method signature and let it bubble up.

耶耶耶 2024-10-16 17:37:46

你可以抛出 RuntimeException 的子类 - 它们不需要 catch()

you may throw a subclass of RuntimeException - they don't require a catch()

软糖 2024-10-16 17:37:46

关键点是,为什么要从 catch 块中抛出新的异常。
如果你使用catch,那么在你的catch中处理你的异常。如果您必须向调用方方法通知异常,那么不要使用 try-catch 捕获异常,而是使用 throws 标记您的方法并让调用方捕获异常。

或者抛出一个 RuntimeException,我发现这个想法不太有用,因为缺乏可读性,那么你不需要用 throws 来签署你的方法。

the key point is, why should you throw a new Exception from a catch block.
if you use catch then handle your exception there in your catch. If you have to inform the caller method with an exception, then don't catch the exception with try-catch, instead, sign your method with throws and let the caller catch the e xception.

or throw a RuntimeException, i find this idea less useful because of lack of readability, then you don't need to sign your method with throws.

原来分手还会想你 2024-10-16 17:37:46

在这里,您遇到了爪哇(如果不是更广泛的)世界上最大的宗教分裂之一。归根结底,那些感觉检查异常很有价值的人(TJ 似乎也这么觉得,我也这么认为)有很多原因,而 Rod Johnson/Spring 学派认为,在 Java 的设计中,检查异常在许多情况下都被使用不应该,比如关闭结果集或套接字,所以因为它在很多情况下被错误地使用,这使得它们变得无用,所以所有异常都应该被取消检查。 Spring 框架中有许多类是标准 Java 对象的非常薄的包装器,但将检查异常转换为未检查异常。它让我发疯!

不管怎样,我强烈同意 TJ 所说的一切,但要知道你可能永远找不到“正确”的答案。

Here you've chanced on one of the biggest religious schisms in the Java, ( if not wider ) , world. It boils down to those that feel, as TJ seems to, and I do too, that checked exceptions are valuable for many reasons, VS the Rod Johnson/Spring school that in the design of Java, checked exceptions were used in many instances where they shouldn't, say closing a resultset or socket, so because it was wrongly used in many cases, it makes them useless so all exceptions should be unchecked. There are many classes in the Spring framework that are very thin wrappers around standard Java objects, but convert checked exceptions to unchecked. It drives me berserk!

Anyway, put me down as strongly agreeing with everything TJ has said, but know that you'll probably never find a "right" answer.

余生共白头 2024-10-16 17:37:46

值得一提的是该领域的一些进展。

首先,在 Java 7 中,只要在 try 块内声明的内容在外部块中捕获或声明,就可以捕获并抛出通用异常。所以这将编译:

void test() throws SQLException {
  try { 
    conn.commit();
  } catch (Throwable t) {
    // do something
    throw t;
  }
}

这里有很好的解释: http://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html


这里描述了另一种方法:http://blog.jooq.org/2012/09/14/throw-checked -exceptions-like-runtime-exceptions-in-java/

您可能想要使用它的原因通常与 lambda 或从某些通用方法抛出异常有关。当我想替换以下重复结构时,我遇到了这个问题:

try {
  do_operation
  flag_success
} catch (Throwable e) {
  flag_error
  throw e;
}

使用以下方法:

public static void wrapExec(RunnableT s) {
    try {
        s.run();
        flag_success
    } catch (Throwable t) {
        flag_error
        doThrow(t);
    }
}

因此将整个 try/catch 块替换为

wrapExec(()->{do_operation})

It's worth mentioning some advances in this area.

First, in Java 7, it's possible to catch and throw generic exceptions, as long as what's declared inside the try block is caught or declared in the outer block. So this would compile:

void test() throws SQLException {
  try { 
    conn.commit();
  } catch (Throwable t) {
    // do something
    throw t;
  }
}

This is well explained here : http://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html


Another way is described here : http://blog.jooq.org/2012/09/14/throw-checked-exceptions-like-runtime-exceptions-in-java/

The reason you may want to use that has often to do with lambdas, or throwing exceptions from some generic methods. I ran into this when I wanted to replace repeating constructs of:

try {
  do_operation
  flag_success
} catch (Throwable e) {
  flag_error
  throw e;
}

With using a method of:

public static void wrapExec(RunnableT s) {
    try {
        s.run();
        flag_success
    } catch (Throwable t) {
        flag_error
        doThrow(t);
    }
}

and therefore replacing the whole try/catch block with just

wrapExec(()->{do_operation})
请帮我爱他 2024-10-16 17:37:46

如果您使用 Java 7 或更高版本,则可以声明该函数以抛出与 try 块中的代码相同的已检查异常。此更改在重新抛出部分中详细描述具有更具包容性的类型检查的异常

简而言之,您可以捕获从 try 块抛出的异常类型的超类型,然后重新抛出它,而无需任何额外的检查异常。因此,如果 try 块中的代码仅引发运行时异常,您仍然可以捕获并重新抛出 Exception 甚至 Throwable,而无需声明任何已检查异常。

If you use Java 7 or newer, you can declare the function to throw the same checked exceptions as the code in the try block. This change is described in detail in the section Rethrowing Exceptions with More Inclusive Type Checking.

In brief, you can catch a supertype of the exception types thrown from a try block and then rethrow it without any extra checked exceptions. So if the code in the try block only throws runtime exceptions, you can still catch and rethrow Exception or even Throwable without declaring any checked exceptions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文