Main Content

对异常作出响应

概述

默认情况下,当引发异常时,MATLAB® 软件会终止当前正在运行的程序。但如果您捕获到程序中的异常,则可以捕获有关出现的问题的信息,并以适合特定条件的方式处理该情况。这需要使用 try/catch 语句。

try/catch 语句

当您的代码中包含会生成不需要的结果的语句时,请将这些语句放入 try/catch 块中,以捕获任何错误并对这些错误进行适当处理。

try/catch 语句类似于下面的伪代码。它包括两部分:

  • try 块,其中包含 trycatch 语句之间的所有行。

  • catch 块,其中包含 catchend 语句之间的所有代码行。

    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

注意

您不能在 trycatch 块中定义嵌套函数。

Try 块

执行时,您的代码进入 try 块并执行每个语句,就好像它是正规程序的一部分一样。如果未遇到任何错误,MATLAB 会完全跳过 catch 块并在 end 语句后继续执行。如果其中任何 try 语句失败,MATLAB 会立即退出 try 块,且不执行该块中的任何其余语句,并进入 catch 块。

Catch 块

catch 命令标记 catch 块的开头,并提供对包含导致异常的信息的数据结构体的访问。这在前面的伪代码中显示为变量 MEME 是一个 MException 对象。出现异常时,MATLAB 创建 MException 对象,并在处理该错误的 catch 语句中返回该对象。

您不需要对 catch 语句指定任何参量。如果您不需要 MException 对象提供的任何信息或方法,仅需指定 catch 关键字。

MException 对象是由失败的程序中的内部代码构造的。该对象的属性中包含有关错误的信息,可用于确定发生了什么以及如何继续操作。MException 对象还提供多种方法的访问权限,从而使您能够对异常作出响应。

进入 catch 块之后,MATLAB 按顺序执行这些语句。这些语句可尝试

  • 解决错误。

  • 捕获有关错误的更多信息。

  • 打开 MException 对象中找到的信息并作出适当响应。

  • 清理受失败代码影响的环境。

catch 块通常以 rethrow 命令结尾。rethrow 使 MATLAB 退出当前函数,并使调用堆栈信息保持为首次引发异常时的状态。如果此函数处于最高级别(即它不由另一个函数调用),则程序终止。如果失败的函数由另一个函数调用,则程序返回到该函数。程序执行过程会继续返回到较高级别的函数,除非其中任何调用是在较高级别的 try 块中进行的,在这种情况下程序会执行各自的 catch 块。

有关如何处理异常的建议

以下是读取图像文件内容的示例。它包括详细的错误处理,并演示一些针对错误可以采取的建议措施。

图像读取函数以几种方式引发和捕获错误。

  • 第一个 if 语句检查函数调用时是否带输入参量。如果没有指定输入参量,程序会引发错误,并建议提供输入参量来更正错误。

  • try 块尝试打开和读取文件。如果打开或读取操作失败,程序会捕获生成的异常并将 MException 对象保存在变量 ME1 中。

  • catch 块用于检查是否找不到指定的文件。如果是,则程序会提供以下可能性:通过使用修改后的扩展名重试操作,以使用常见的文件扩展名变化形式(例如 jpeg 而不是 jpg)。这是通过嵌套在原始 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 对象添加到第二个对象的 cause 字段中。

  • MException 对象添加建议的更正。

  • 重新引发异常。这会停止程序的执行并显示错误消息。

此外,建议清理掉任何不需要的错误结果。例如,关闭在错误发生后保持打开的图窗。