C#の例外処理構造と制御フローの違いをやさしく解説!初心者でも理解できる基本知識
生徒
「C#の制御フローと例外処理って、どう違うんですか?」
先生
「いい質問ですね。どちらもプログラムの流れをコントロールするために使いますが、目的や使い方が異なりますよ。」
生徒
「なんだか難しそう…。初心者にもわかりやすく教えてもらえますか?」
先生
「もちろんです!簡単なたとえを使いながら、基礎からしっかり解説しますね。」
1. 制御フローとは?
C#の制御フローとは、プログラムの命令をどの順番で実行するかを決める仕組みのことです。代表的なものには、if文、for文、while文、switch文などがあります。
たとえば、「もし〇〇なら〜する」とか、「10回同じことを繰り返す」といった処理の流れを決めるために使います。
具体的な例を見てみましょう。
int number = 5;
if (number > 0)
{
Console.WriteLine("正の数です。");
}
正の数です。
この例では、変数numberが0より大きければ「正の数です。」と表示されます。これが制御フローです。
2. 例外処理とは?
例外処理は、プログラム中で「予期しないエラー」が発生したときに、そのエラーをキャッチして、プログラムを止めずに対処する仕組みです。
例えば、ゼロで割ったり、存在しないファイルを開こうとしたときにエラーになりますよね。それを例外(エラー)と呼び、try〜catchブロックを使って処理します。
以下の例を見てみましょう。
try
{
int x = 10;
int y = 0;
int result = x / y;
Console.WriteLine(result);
}
catch (DivideByZeroException)
{
Console.WriteLine("ゼロで割ることはできません。");
}
ゼロで割ることはできません。
このコードでは、10 ÷ 0 という計算が例外を発生させますが、catchブロックで受け止めて、エラーメッセージを表示しています。
3. 制御フローと例外処理の違い
ここまでで、それぞれの使い方がわかりましたね。それでは、制御フローと例外処理の違いを整理してみましょう。
- 制御フロー:プログラムの通常の流れを制御(分岐や繰り返し)する。
- 例外処理:エラーが発生したときに、プログラムが止まらないようにする。
たとえるなら、制御フローは「信号機」や「交差点」で進む道を決めるようなもの。例外処理は「事故」が起きたときに、救急車や警察が対応する仕組みに近いです。
4. try-catch-finallyの基本構造
C#では、例外処理に使う構文としてtry〜catch〜finallyがあります。それぞれの役割は以下の通りです。
try:例外が起きるかもしれない処理を書く。catch:例外が起きたときに実行する処理。finally:例外の有無にかかわらず、最後に必ず実行される処理。
try
{
// 例外が起こる可能性のあるコード
}
catch (Exception ex)
{
// 例外が起きたときの処理
}
finally
{
// 最後に必ず実行される処理
}
finallyは、たとえばファイルや接続の後始末など、「絶対に実行してほしい処理」を書くときに使います。
5. 例外処理のないコードの危険性
例外処理をしないと、エラーが発生した時にプログラムが途中で止まってしまいます。
int[] array = { 1, 2, 3 };
Console.WriteLine(array[5]);
System.IndexOutOfRangeException: インデックスが配列の範囲外です。
このように、配列の範囲外にアクセスすると例外が発生し、プログラムはクラッシュします。例外処理はプログラムの安全性を高めるために必須です。
6. よく使う例外クラス
C#では、さまざまな例外クラスが用意されています。以下はよく使われる例外の一部です。
DivideByZeroException:ゼロで割ったときIndexOutOfRangeException:配列などのインデックスが範囲外NullReferenceException:nullの値にアクセスしようとしたときFileNotFoundException:指定したファイルが存在しないとき
このような例外をcatchブロックで指定することで、より的確なエラー処理ができます。
7. 例外処理と制御フローを組み合わせた例
最後に、例外処理と制御フローを組み合わせた簡単なサンプルを紹介します。
for (int i = 0; i < 3; i++)
{
try
{
Console.Write("割られる数を入力してください:");
int x = int.Parse(Console.ReadLine());
Console.Write("割る数を入力してください:");
int y = int.Parse(Console.ReadLine());
Console.WriteLine("結果:" + (x / y));
}
catch (DivideByZeroException)
{
Console.WriteLine("0では割れません。もう一度やり直してください。");
}
}
for文(制御フロー)で繰り返しを行い、その中でtry-catchを使って例外を処理しています。
まとめ
C#の例外処理と制御フローは、見た目は似ているようでも、役割がまったく異なる仕組みです。制御フローは、if文やfor文などを使って「予定通りの手順」を進めるための道筋をつくるものです。プログラムが迷子にならないように、順番を決めたり、条件によって分岐させたり、同じ処理を繰り返したりするために存在します。正しい手順を整理しながら処理を組み立てると、読みやすく安全なコードになります。特に初心者でも理解しやすく、実務でも一番よく使う基本的な要素です。
一方、例外処理は「予定外の出来事」が起きたときに力を発揮します。同じ処理を正しく流そうとしても、必ず想定外の状況が存在します。たとえば、ファイルが見つからない、数値が不正、ネットワークが切れてしまう、入力が空で計算ができないなど、現実のプログラムは必ずどこかでトラブルが起こります。そこで、try-catchという仕組みを使い、問題が発生してもプログラムを止めずに次の処理へと進めます。
特に、DivideByZeroExceptionやIndexOutOfRangeExceptionなど、C#には多くの例外クラスが標準で用意されています。もし例外処理がなければ、ちょっとしたミスで動作が完全に止まり、ユーザーの操作もデータ保存も途中で失われてしまいます。例外処理は、プログラムを安心して使えるようにするための保険のようなものです。
また、try-catch-finallyを使えば、例外が起きても最後に必ず実行したい処理を書くことができます。ファイルのクローズ処理や、データベース接続の解放など、後片付けが必要な処理で特に役立ちます。これは、日常生活で例えると、失敗しても最後にドアの鍵だけは閉めて帰るようなイメージです。
実際の開発では、制御フローと例外処理は組み合わせて使うことが多くなります。繰り返しのループの中で例外が起きても止まらないようにしたり、複数の条件の中で問題が起きたときにメッセージを表示したり、ログを保存したりするなど、使い方次第でプログラムは非常に強くなります。
下のコードは、例外処理と制御フローを組み合わせた、少し応用的な例です。数値入力を繰り返し、例外が出ても処理が途切れません。
制御フローと例外処理を合わせたサンプル
for (int i = 0; i < 5; i++)
{
try
{
Console.WriteLine("整数を入力してください:");
int value = int.Parse(Console.ReadLine());
if (value % 2 == 0)
{
Console.WriteLine("偶数です。");
}
else
{
Console.WriteLine("奇数です。");
}
Console.WriteLine("割る数を入力してください:");
int div = int.Parse(Console.ReadLine());
Console.WriteLine("結果:" + (value / div));
}
catch (FormatException)
{
Console.WriteLine("数字として認識できません。もう一度入力してください。");
}
catch (DivideByZeroException)
{
Console.WriteLine("0では計算できません。もう一度試してください。");
}
finally
{
Console.WriteLine("入力処理が完了しました。\n");
}
}
この例では、数値の偶奇判定という制御フローと、計算処理中の例外を同時に扱っています。formatエラーもゼロ除算もcatchで拾い、最後には必ずfinallyが実行されます。こうして、ユーザーに優しいプログラムが作れます。プログラムが途中で止まらないのはとても大切で、例外処理を入れるだけで印象が大きく変わります。
C#は非常に整った言語で、例外の種類ごとにcatchを書いたり、まとめて例外を扱ったり、必要に応じてログを残したりもできます。単純なif文だけでは対処しきれなかった問題も、例外処理を使えば現実的で信頼性のあるプログラムへと変わります。日常の中でも、すべてが予定通りに進むわけではありません。プログラムも同じで、例外を前提として書くことで安全性が大幅に向上します。
制御フローと例外処理は、どちらか一方ではなく、両方を使いこなすことで初めて力を発揮します。条件分岐、繰り返し、例外補足、後処理、この4つを自然につなげられるようになれば、初心者から中級者へ一歩進んだといえるでしょう。
生徒
「制御フローは、プログラムの普通の流れを決めるんだって理解できました。ifやforは、やっぱり基本ですね。」
先生
「その通りです。ただ、現実のプログラムはいつも正しい入力が来るとは限りません。そこで例外処理が必要になります。」
生徒
「例外処理を入れないと、プログラムが途中で止まってしまうんですよね。怖いですね…。」
先生
「特にユーザー入力やファイル操作は例外が多い場面です。try-catchで補足すれば、落ち着いて対応できます。」
生徒
「finallyも便利ですね。途中でエラーが出ても、後処理がちゃんと動くのが安心です。」
先生
「最後まで動いてくれるコードは信頼できますからね。実務でも絶対使うので、ぜひ身につけてください。」