例外とエラーについて調べたこと

Jul 13, 2016 ( Feb 11, 2022 更新 )

例外とエラーについて調べたくなった経緯

「Let It Crash」というフレーズの出典を調べていたところ、Making Reliable Distributed Systems in the Presence of software errorsというErlang設計者が書いたドキュメントに行き着いた。 このドキュメントの中では例外とエラーを以下のように定義していた。

  • exceptions occur when the run-time system does not know what to do.
    • 例外はrun-time systemがどう対処していいかわからないもの
  • errors occur when the programmer doesn’t know what to do.
    • エラーはプログラマがどう対処していいかわからないもの

今まで自分は例外は例外、というひとつの概念でしか考えられていなかったので、

unchecked, checked例外

Unchecked Exceptions — The Controversy (The Java™ Tutorials > Essential Classes > Exceptions)

  • unchecked exception
    • JavaではRuntimeException, Error, またはこれらのサブクラス
    • Javaではこれらの例外クラスはtry-catchしなくてもコンパイルエラーにならない
      • Javaのプログラマーはしばしば、try-catchの煩雑な記述を避けるために例外をRuntimeExceptionを継承してthrowすることがあるという。そして上記の文章ではこのようなthrowの仕方を推奨していない
  • checked exception
    • try-catchすべき例外
    • JavaではExceptionクラスとして表現

Javaのエラーと例外

JavaにはThrowrableというクラスがあり、これのサブクラスとしてExceptionとErrorがある。 Exceptionはtry-catchしなければいけない(さもなければコンパイルできない)が、Errorはabnormalな状況なのでcatchすべきではないとある。(しかしcatch自体はできる) RuntimeExceptionはExceptionの子クラスだが、unchecked exceptionなのでtry-catchしなくてもコンパイルは通る。(なぜこのような設計になったのか?) RuntimeExceptionは例外、すなわちプログラマが対処できる、しかしコンパイラはチェックしない(できない?)

Armstrong Thesisと同じ「例外」の考え方が書いてあった。

Why did the designers decide to force a method to specify all uncaught checked exceptions that can be thrown within its scope? Any Exception that can be thrown by a method is part of the method’s public programming interface. Those who call a method must know about the exceptions that a method can throw so that they can decide what to do about them. These exceptions are as much a part of that method’s programming interface as its parameters and return value.

なぜRuntimeExceptionはuncheckedなのか?

JavaではExceptionはプログラムのインターフェースの1部であり、例外のthrowを宣言すべきとされる。 ではなぜRuntimeExceptionはuncheckedなのか。 JavaではRuntimeExceptionはAPIのクライアント(API利用側のコード?)が、RuntimeExceptionからrecoverできないことを表しているのだという。オブジェクトだと思っていたものがnullだったり、ゼロで割り算しようとした場合など。 また、RuntimeExceptionはプログラムのいろいろなところで発生するので、これを宣言すると煩雑になるということでthrows宣言を必須でなくしている。 ※必須ではない、というだけでcatchはできる。

JavaはRuntimeExceptionの使い方として、methodに対するユーザの入力値が正しくない場合を挙げている。 ただし、一般的にはRuntimeExceptionをthrowすべきではないという。いちいち宣言するのは煩わしいから、とのこと。

Here’s the bottom line guideline: If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.

  • 回復できる場合はchecked
  • 回復できない場合はunchecked

とあるが、結局のところRuntimeExceptionはコンピュータ的には回復不可能なんだけど、プログラマ的には回復できるとする例外なのかな? 例えば、コンピュータ的は0で割れないのに、0で割りますって言われたら何もできません、終了って感じだけど、プログラマ(人間)的には0で割れませんでした、じゃあ後処理(0で割れなかったら他のmethodに何か別の処理をやらせるとか?出力インターフェースに何かメッセージ渡すとか?)やりましょう、という場合があるよねっっていう話?

furukawaさんの記事

Node.js における Promise を使った例外処理 - from scratch

  • uncaughtExceptionは、V8でNode.jsでcatchされなかった例外をcatchして、Node.jsでuncaughtExceptionイベントを発生させている。
  • V8でtry-catchしていたら何かの処理が途中で中途半端になっている可能性がある。なので終了させたほうがよい。
  • unhandledRejectionは、JavaScriptのコードからC++の%PromiseRejectEvent(おそらくprocess.on('unhandledRejection')を発生させる関数と思われる)を呼んでいるだけ。V8の例外処理と関係ない。
Return to top