前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >四问四答Java异常抛出和处理

四问四答Java异常抛出和处理

作者头像
小草学习屋
发布2023-11-22 09:49:56
4860
发布2023-11-22 09:49:56
举报
文章被收录于专栏:小草学习屋

抛什么类型的异常?什么时候抛自定义异常?如何自定义异常?什么时候抛出和处理异常?

为了符合阅读习惯,下文直接用xx Exception代替称呼各种异常。

基本概念

先来张经典异常族谱图:

exception.png
exception.png
  • Throwable:当对象为此类或其子类时,才能通过Java的throw语句抛出。
  • Error:系统错误,由JVM处理,开发者无需处理。例如:OutOfMemoryError、StackOverflowError。
  • Exception:异常,开发者需要关注。又分为Checked Exception和UnChecked Exception。
    • Checked Exception/Compile-time Exception:此类异常需要在编译时处理。若方法声明抛出此类异常,开发者需要在程序捕获。例如:GeneralSecurityException、IllegalClassFormatException。
    • UnChecked Exception/Runtime Exception:此类异常在编译时无需处理,运行时抛出。抛出后,当前运行的线程将中断。例如:NullPointerException、IllegalArgumentException。

抛什么类型的异常

需要处理且使用者有能力处理的场景,抛Checked Exception。

stripe-java的request方法为例:

代码语言:javascript
复制
  /**
   * Sends the given request to Stripe's API, and returns a buffered response.
   *
   * @param request the request
   * @return the response
   * @throws ApiConnectionException if an error occurs when sending or receiving
   */
  @Override
  public StripeResponse request(StripeRequest request) throws ApiConnectionException {
    final StripeResponseStream responseStream = requestStream(request);
    try {
      return responseStream.unstream();
    } catch (IOException e) {
      throw new ApiConnectionException(
          String.format(
              "IOException during API request to Stripe (%s): %s "
                  + "Please check your internet connection and try again. If this problem persists,"
                  + "you should check Stripe's service status at https://twitter.com/stripestatus,"
                  + " or let us know at support@stripe.com.",
              Stripe.getApiBase(), e.getMessage()),
          e);
    }
  }

该方法向stripe API发送请求,它抛出了一个ApiConnectionException,并附上供使用者参考的处理信息。

另外,还有一些可能导致程序崩溃的场景,特别是可能被坏人利用、篡改信息导致使用者程序不断崩溃的情况,酌情抛出Checked Excpetion让使用者处理。

总之,从使用者角度出发,抛出的异常要便于使用者处理,并尽量保证程序健壮。

什么时候抛自定义异常

有可使用的已定义异常,优先使用;没有时才考虑自定义异常。

抛出的异常种类越多,使用者的理解、处理成本越高。因此,尽量使用已有异常,当需要抛业务相关的异常,才考虑自定义。

自定义异常注意事项

语义清晰、带有业务意义、保留原异常数据。 一般自定义异常都为Checked Exception。如果抛出自定义的Unchecked Exception,使用者没有关注到,当程序上线了,突然出现一个不认识的Unchecked Exception,他的心情一定很复杂。

以GeneralSecurityException为例:

代码语言:javascript
复制
package java.security;
public class GeneralSecurityException extends Exception {

    private static final long serialVersionUID = 894798122053539237L;

    public GeneralSecurityException() {
        super();
    }

    public GeneralSecurityException(String msg) {
        super(msg);
    }

    public GeneralSecurityException(String message, Throwable cause) {
        super(message, cause);
    }

    public GeneralSecurityException(Throwable cause) {
        super(cause);
    }
}

可以看到定义异常有以下要点:

  • serialVersionUID

在序列化和反序列化中作为唯一标识。因为Throwable实现了Serializable接口,支持序列化和反序列化,所以所有异常都定义要它。

  • 自定义message 异常描述信息。便于使用者定位、排查问题。最好提供提供处理指引,像上面提到的stripe-java的request方法的错误描述。
  • 原始Throwable类 引起该异常的源头。保留完整信息,便于使用者定位、排查问题。

对于具体业务,如果有需要,我们还可以抽象合适的异常层级或者添加业务信息。例如stripe-java的StripeException。它是Stripe自定义异常的基类,封装了业务相关的requestId、Code、statusCode等。

什么时候抛出和处理异常

尽量早地抛出异常,尽量晚地捕获异常。

类比打工人的早C晚A,对异常来说,就是早T(throw)晚C(catch)。

尽量早地抛出异常,才能更好地定位、解决问题。

Exceptions in Java中举了一个例子:多线程执行时,一个线程遇到ConcurrentModificationException异常没有及时抛出,为定位和解决问题带来巨大代价。

在最合适的时候才捕获异常,才能更好地解决问题。

10 Best Practices to Handle Java Exceptions中有一条原则:只在可以处理的时候捕获并处理,不能处理的异常就抛出去。

在上面的stripe-java的request方法中,可以选择在request内调用内部方法遇到异常时就捕获并处理,例如主动进行1次重试,遇到特定httpcode作特定操作。

但这不是最好的处理方式。抛出异常让使用者处理,具有拓展性,用户体验最优。使用者能够根据自身需要,选择什么场景重试,什么场景不重试,什么场景重试几次等等。

小结

在业务程序中抛出自定义异常时,我曾经想过只定义一个xxExcpetion,然后用错误码来代表不同的异常类型。听起来有点像Java和C++的城中结合风。

这样做不是不行,只是异常含义不明确,还需要使用者二次转义。如果你的异常体系已经很庞大,其中一种类型异常本身包括二次转义(例如,http请求不同返回码含义不同),这也是一个可取的方式。

还有,在获取不到数据时,是返回null,还是抛出NoSuchElementException,还是抛出自定义异常,也是一个在不同场景下有不同答案的问题。

遇到问题时,可以看最佳实践,或者看看别人怎么做的。看多了就会发现,更不懂了(指我)。

欢迎和我分享你的实践经验和观点,拯救我于水深火热的菜狗队列之中。

小彩蛋:你知道Java中的常见异常都是什么意思吗?点开这里来看看吧

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-11-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基本概念
  • 抛什么类型的异常
  • 什么时候抛自定义异常
  • 自定义异常注意事项
  • 什么时候抛出和处理异常
  • 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档