8
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Delphiの例外処理を理解する

Last updated at Posted at 2020-05-14

JavaやらPHPとかの例外処理をやっていたら、Delphiの例外処理って特殊というか、誤って理解している部分があったと認識しましたので、改めてまとめてみました。

Javaの例外処理

Javaの例外処理はスッキリしている(と思います)。

Java
try {
    例外が起きるかもしれない処理
} catch(AException e) {
    例外AExceptionが発生した場合の処理
} catch(BException e) {
    例外BExceptionが発生した場合の処理
} catch(CException | DException e) {
    例外CExceptionかDExceptionが発生した場合の処理
} finally {
    例外が起きても起きなくても行う処理
}
tryブロックを抜けたら行う処理

catch節は、捕捉する例外に応じて続けることができます。finally節は、処理が不要なら省略できます。
なお、Java 7以降ではtry~catch~resources文が使えるようになっているそう。これはfinally節で明示的に行っていたリソースの解放を明示的な記述なしに行える書式ですが、この投稿の趣旨とは関係ないので省略します。

PHPの例外処理

PHPの例外処理は、Javaに倣って作ったのか、構文も動きもほとんど同じです(多分)。catch節で、捕捉する例外をパイプ(|)で結んで複数指定できるのもJavaと同じです。

Delphiの例外処理

これに対して、Delphiの例外処理はちょっとややこしいです。まず、書式が2つあること。

try~except文
try
    例外が起きるかもしれない処理
except
    on E:AException do 例外AExceptionが発生した場合の処理
    on E:BException do 例外BExceptionが発生した場合の処理
end;
tryブロックを抜けたら行う処理
try~finally文
try
    例外が起きるかもしれない処理
finally
    例外が起きても起きなくても行う処理
end;
tryブロックを「何事もなく」抜けたら行う処理

双方が合わさったtry~except~finallyというものは存在しないのです。

しかも、try~finallyでは例外が起きてもっとも外側のfinallyブロックの中身を実行したら、プロシージャなり関数なりからも抜けてしまう、つまりexitしてしまうので要注意です。つまり、finallyブロック以降に書かれた処理は実行されません。本当に、「最後に」実行する処理になります。

そういう意味では、try~finallyは厳密には例外処理ではないかもしれません。処理されない例外を捕捉して、後処理までやってあげたよ。けど処理を続けても意味がないので抜けるね、という感じでしょうか。

んじゃ、Javaなんかのようにするにはどうしたらいいの?ということですが、これはtryブロックを入れ子にするしかないようです。

try
    try
        例外が起きるかもしれない処理
    except
        on E:AException do 例外AExceptionが発生した場合の処理
        on E:BException do 例外BExceptionが発生した場合の処理
    end;
finally
    例外が起きても起きなくても行う処理
end;
tryブロックを抜けたら行う処理

内側のtryブロックで例外が発生したら、そこのexceptブロックにある例外処理が実行されます。そして、例外の有無にかかわらず外側のfinallyブロックに処理が移ります。ここで大事なのは、外側のtryブロックを抜けても処理が継続するということです。内側のtryブロックで例外が発生しても、それはexceptブロックで処理されて例外がクリアされているので、finallyブロックにとっては例外が発生していないよ、ということになります。ややこしいですね。

とはいえ、これでJavaのような例外処理が実装できるわけです。

ちなみに、tryブロック内でexitしても、すべてのfinallyブロックが実行されますが、もっとも外側のfinallyブロックより後の処理は実行されません。つまり、exitするけど、すべてのfinallyをやっておくよ、ということになります。

ということで、何重にも入れ子になったtry~endは可読性を下げそうなので、できるだけ避けたほうが無難ですね。

8
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?