ビジネスにおけるカスタム例外の Exception または RuntimeException? なぜ?

この記事は「Golden Stone Project. Share 60,000 Cash Prize」に参加しています。

順序

今日は異常について同僚と雑談したので、ここにまとめておきます

 目前公司中使用的 自定义异常是 extend RuntimeException 

継承例外

ビジネス開発で例外を継承する場合は、RuntimeException または Exception を拡張しますか?

RuntimeException に違いないと思ったのですが、なぜでしょうか? 例外を選択できませんか?

RuntimeException と Exception の違い

これについて話す前に、私たちのニーズが何であるかを判断する必要があります

必要

要件は、ビジネスで使用される例外をカスタマイズすることです

要件を決定した後、分析します

image.png

ここで、ビジネス開発は基本的にランタイム例外であることがわかっているため、RuntimeException を使用します。

ここで質問なのですが、普段 IO 操作をしているとモテて投げたり、キャッチしてみたりすることが多いのですが、それはどの属性のことをするのでしょうか?

最初にコードを見てください

image.png

しかし、この例外は createNewFile メソッドによってスローされる例外が RuntimeException であるかどうかとは関係がないためです。

public boolean createNewFile() throws IOException {
    SecurityManager security = System.getSecurityManager();
    if (security != null) security.checkWrite(path);
    if (isInvalid()) {
        throw new IOException("Invalid file path");
    }
    return fs.createFileExclusively(path);
}
复制代码

これは関連しており、RuntimeException 以外では throw または try catch が必要ですが、これは自動ではなく、開発者がコードを記述するときに行う必要があることです。つまり、この例外をチェックする必要があります。

その他の注意事項プログラミング言語の原則の本の434ページの一部

image.png

この作品は、ビジネスでどちらを使用するかという疑問を残します。

image.png

他の RuntimeException コードとどう違うのですか?

違いはありません。つまり、1 つは RuntimeException を継承し、もう 1 つは Exception を継承し、それ以外は何も継承しません。

トランザクションで例外をインターセプトする

我们到这 知道了继承异常应该用RuntimeException,但是我们应该知道 阿里规约手册 中有这么一段

1、让检查异常也回滚:你就需要在整个方法前加上@Transactional(rollbackFor=Exception.class)

2、让非检查异常不回滚:
需要加入@Transactional(notRollbackFor=RunTimeException.class)

3、不需要事务管理(or 日志丢失)
需要加入@Transactional(propagation=Propagation.NOT_SUPPORTED)

为什么?

Exception类下面除了runtimeException还有SQLException和ioException

如果方法没有抛出runtimeException 而是抛出 SQLExceptionioException那么事务是不会回滚的

那么这就结束了吗?在我们编码过程中,如果方法要抛出一些可检查异常时是需要throws进行显式指定异常类的

那么问题来了,我们都知道方法签名中默认是throws RuntimeException,已知SqlException不是RuntimeException的子类

小总结

@Transactional(notRollbackFor=RunTimeException.class) 是因为抛弃了 IO异常和 SQL异常等情况,所以 我们 应该用 Transactional(rollbackFor=Exception.class)

为什么 不是 rollbackFor = Throwable.class 呢

これを明示的に指定する必要はありません rollbackFor = Throwable.class 。Spring はデフォルトで、トランザクションが発生した場合にロールバックします错误**

本来、non-RuntimeException以外はトランザクション管理に入っている

デフォルト構成では、Spring Framework のトランザクション インフラストラクチャ コードは、チェックされていない例外、つまり、RuntimeException のインスタンスまたはサブクラスである例外がスローされたランタイム ロールバックのトランザクションのみをマークします。  (エラーも発生します - デフォルトではロールバックが発生します)トランザクション メソッドからスローされたチェック例外は、既定の構成ではロールバックを引き起こしません。**

または見る DefaultTransactionAttribute

public boolean rollbackOn(Throwable ex) { 
        return (ex instanceof RuntimeException || ex instanceof Error); 
}
复制代码

特定の場所docs.spring.io/spring-fram…

要約すると、トランザクションには @Transactional(rollbackFor=Exception.class) を使用する必要があります

例外に対する他のミドルウェアのアプリケーション シナリオとその理由は何ですか?

まずはナコスを見てください

//检查 异常
public class NacosException extends Exception {
}
复制代码

使用時

image.png

投げとトライキャッチがあります

では、何が Nacos 例外をスローしているのでしょうか?

private <T extends Response> T requestToServer(AbstractNamingRequest request, Class<T> responseClass)
        throws NacosException {
    try {
        xxx
    } catch (Exception e) {
        throw new NacosException(NacosException.SERVER_ERROR, "Request nacos server failed: ", e);
    }
    throw new NacosException(NacosException.SERVER_ERROR, "Server return invalid response");
}
复制代码

ロケット

まず実行時例外を見てください

运行时异常
public class AclException extends RuntimeException {
}
复制代码

使用する

public static void verify(String netaddress, int index) {
    if (!AclUtils.isScope(netaddress, index)) {
        //运行的时候 发生异常
        throw new AclException(String.format("Netaddress examine scope Exception netaddress is %s", netaddress));
    }
}
复制代码

別のチェック済み例外を見てください

public class MQClientException extends Exception {
}
复制代码
throws MQClientException, RemotingException, MQBrokerException
复制代码

使用する

public TransactionSendResult sendMessageInTransaction(final Message msg,
    final LocalTransactionExecuter localTransactionExecuter, final Object arg)
    throws MQClientException {
    TransactionListener transactionListener = getCheckListener();
    if (null == localTransactionExecuter && null == transactionListener) {
        //如果为空 client 异常
        throw new MQClientException("tranExecutor is null", null);
    }
 }
复制代码

要約する

ミドルウェアのほとんどは、クライアント接続の失敗、リモート接続のタイムアウト、および検査中の例外であるサーバー側の例外であるため、Exception を拡張する必要があります。

しかし

  1. ビジネス開発中、ほとんどの判断は空であり、RunntimeException を実行時例外にすることをお勧めします。
  2. 検査中は常に例外をスローする必要があり、コードのクリーンさの観点から RunntimeException をお勧めします

要約する

  1. リモート接続の利用・異常利用チェックが異常で、相手が異常を感じられるようにする
  2. ビジネスのコードはランタイム例外を使用します

ビジネスに extends RuntimeException を使用することを引き続きお勧めします。残りはビジネス シナリオに従って選択する必要があります。

考える

 ok 那你说 远程连接使用 检查时异常,那feign 属于远程rpc,他的异常就必须是 检查时异常么?为什么? 

おすすめ

転載: juejin.im/post/7166976169152086024