Main Content

例外への応答

概要

MATLAB® ソフトウェアの既定の設定では、例外がスローされると現在実行中のプログラムを停止します。ただし、プログラムで例外をキャッチすると、誤りに関する情報を収集し、適切な方法で特定の状況に対処できます。このためには、try/catch ステートメントが必要です。

try/catch ステートメント

期待どおりの結果が生じない可能性のあるコードがステートメントに含まれる場合は、これらのステートメントを try/catch ブロックに入れます。エラーが発生した場合はキャッチされ、適切に処理されます。

try/catch ステートメントは、次の疑似コードにようになり、次の 2 つの部分で構成されます。

  • trycatch ステートメント間のすべての行を含む、try ブロック。

  • catchend ステートメント間のすべての行を含む、catch ブロック。

    try
       Perform one ...
          or more operations
A   catch ME
       Examine error info in exception object ME
       Attempt to figure out what went wrong
       Either attempt to recover, or clean up and abort
    end

B   Program continues

このプログラムは、try ブロックのステートメントを実行します。エラーが見つかると、try ブロックの残りのステートメントをスキップし、catch ブロックの始め (上の A の位置) にジャンプします。try ブロックのすべての演算が成功すると、catch ブロックが完全にスキップされ、end ステートメントに続く最初の行 (点 B) に進みます。

trycatchend コマンドと、trycatch ブロックのコードは、別の行に指定することを推奨します。同じ行にこれらのコンポーネントのいずれかを組み合わせる場合は、以下のようにコンマで区切ります。

try, surf, catch ME, ME.stack, end
ans = 
    file: 'matlabroot\toolbox\matlab\graph3d\surf.m'
    name: 'surf'
    line: 49

メモ

try または catch ブロック内では、入れ子関数を定義することはできません。

Try ブロック

実行時に、コードは try ブロックに入り、通常のプログラムの一部と同様に各ステートメントが実行されます。エラーが見つからなかった場合、MATLAB では catch ブロックが完全にスキップされ、end ステートメントに従って実行を続けます。try ステートメントのいずれかにエラーがあると、MATLAB はそのブロックの残りのステートメントは実行せずに、すぐに try ブロックを終了し、catch ブロックに入ります。

Catch ブロック

catch コマンドは、catch ブロックの開始をマークし、例外の原因についての情報を含むデータ構造へのアクセスを提供します。これは、以前の疑似コードの変数 ME として表示されます。MEMException オブジェクトです。例外が発生すると、MATLAB は MException オブジェクトを作成し、そのエラーを処理する catch ステートメントに含めてオブジェクトを返します。

catch ステートメントでは引数を指定する必要はありません。MException オブジェクトで提供される情報やメソッドが必要でない場合は、catch キーワードのみを指定します。

MException オブジェクトは、エラーのあるプログラムの内部コードによって作成されます。このオブジェクトは、エラーに関する情報を含むプロパティをもちます。この情報は、何が起こったかを特定したり、対処方法を決定する際に役立ちます。MException オブジェクトではメソッドへのアクセスも提供され、例外に応答できるようになります。

catch ブロックに入ると、MATLAB ではステートメントが順番に実行されます。これらのステートメントでは、以下を試みることができます。

  • エラーの解決

  • エラーに関する詳細情報の収集

  • MException オブジェクトの情報に基づいた、適切な応答

  • エラーの発生したコードの残した環境のクリーンアップ

catch ブロックは、多くの場合、rethrow コマンドで終わります。rethrow では、例外が初めにスローされたときの状態に呼び出しスタックの情報を保ち、MATLAB で現在の関数を終了させます。この関数が最上位にある場合、つまり、他の関数によって呼び出されなかった場合は、プログラムが終了します。エラーの発生した関数が別の関数で呼び出された場合は、呼び出し側の関数に戻ります。プログラムは実行を続け、上位レベルの関数に戻ります。ただし、呼び出しのいずれかが上位レベルの try ブロック内で行われた場合は例外で、この場合は対応する catch ブロックが実行されます。

例外の処理方法についての提案

以下の例では、イメージ ファイルの内容を読み込みます。これには詳細なエラー処理が含まれており、エラーに対して実行できる提案アクションの一部について説明します。

イメージを読み取る関数がエラーをスローおよびキャッチする方法にはいくつかあります。

  • 最初の if ステートメントは、関数が入力引数を指定して呼び出されているかどうかをチェックします。入力引数が指定されていない場合、プログラムはエラーをスローし、エラーを修正するための入力引数を提案します。

  • try ブロックでは、ファイルを開いて読み取りが試行されます。ファイルを開けなかった場合や、読み込みに失敗した場合は、プログラムで結果の例外がキャッチされ、MException オブジェクトが変数 ME1 に保存されます。

  • catch ブロックでは、指定されたファイルが見つからなかったかどうかのチェックが行われます。見つからなかった場合は、ファイル名拡張子の一般的なバリエーション (たとえば、jpg の代わりに jpeg) を使用して、操作が再試行されます。これは、元の try/catch に入れ子にされた try/catch ステートメントを使用して行われます。

function d_in = read_image(filename)

% Check the number of input arguments.
if nargin < 1
    me = MException('MATLAB:notEnoughInputs','Not enough input arguments.');
    aac = matlab.lang.correction.AppendArgumentsCorrection('"image.png"');
    me = me.addCorrection(aac);
    throw(me);
end

% Attempt to read file and catch an exception if it arises.
try
   fid = fopen(filename,'r'); 
   d_in = fread(fid); 
catch ME1 
   % Get last segment of the error identifier.
   idSegLast = regexp(ME1.identifier,'(?<=:)\w+$','match'); 

   % Did the read fail because the file could not be found? 
   if strcmp(idSegLast,'InvalidFid') && ...
      ~exist(filename,'file')

      % Yes. Try modifying the filename extension.
      switch ext
      case '.jpg'    % Change jpg to jpeg 
          filename = strrep(filename,'.jpg','.jpeg');
      case '.jpeg'   % Change jpeg to jpg 
          filename = strrep(filename,'.jpeg','.jpg');
      case '.tif'    % Change tif to tiff 
          filename = strrep(filename,'.tif','.tiff');
      case '.tiff'   % Change tiff to tif 
          filename = strrep(filename,'.tiff','.tif');
      otherwise 
         fprintf('File %s not found\n',filename);
         rethrow(ME1);
      end 

      % Try again, with modified filenames.
      try
         fid = fopen(filename,'r'); 
         d_in = fread(fid);
      catch ME2
         fprintf('Unable to access file %s\n',filename);
         ME2 = addCause(ME2,ME1);
         rethrow(ME2)
      end 
   end 
end

この例では、次のような、例外への応答で実行できる操作をいくつか説明します。

  • MException オブジェクトの identifier フィールドを、エラーの考えられる原因と比較。この場合、関数は識別子がファイルが見つからなかったこととを示す 'InvalidFid' で終了しているかどうかをチェックします。

  • 入れ子になっている try/catch ステートメントを使用して、改善された入力で操作を再試行。この場合、関数はファイル名拡張子の既知のさまざまなバリエーションを使用して、開く操作と読み取る操作を再試行します。

  • 適切なメッセージを表示。

  • 最初の MException オブジェクトを 2 番目の cause フィールドに追加

  • 推奨される修正を MException オブジェクトに追加。

  • 例外を再スロー。これによりプログラムの実行が停止し、エラー メッセージが表示されます。

エラーによって引き起こされた望ましくない結果もクリーンアップすることをお勧めします。たとえば、エラーの発生後に開いたままになっている図を閉じます。