MATLAB 中异常信息的捕获

概述

当 MATLAB 抛出异常时,它会捕获产生错误的信息,并将之保存在类 MException 对象的数据结构中。可以在程序中止之前捕获异常并通过 catch 命令访问为此异常构造的对象获得 MException 对象的访问权限。当抛出异常以响应用户代码中的错误时,将不得不创建一个新的 MException 对象并在该对象中存储有关错误的信息。本节主要说明 MException 类和该类构造的对象。

MException 类

下图显示了 MException 类对象的一种可能配置。该对象有四个属性:标识符(identifier),消息(message),堆栈(stack)和原因(cause)。每一属性都表示 MException 对象结构的一部分。堆栈字段是 N×1 的附加结构数组,每个结构标识一个函数,和来自调用堆栈的行号。 cause 字段是 MException 对象的 M×1 胞元数组,每个数组表示与当前对象相关的异常。

对象构造函数

任何检测到错误并抛出异常的代码必须构造一个 MException 对象,在该对象中记录和传输有关错误的信息。 MException 构造函数的语法是

ME = MException(identifier, message)

其中 identifier 是一种 MATLAB 消息标识符,形式为

component:mnemonic

用单引号括起来。消息是用单引号括起来的文本,用于描述错误。 输出 ME 是生成的 MException 对象。

如果你要响应异常而不是抛出异常,则不必构造 MException 对象。 该对象已由最初检测到错误的代码构造和填充。

MException 类的属性

MException 类有四个属性(identifier,message,stack,cause,)。 每一属性都表示 MException 对象结构的一部分,并且是只读的。

如果你忘了输入参数,直接调用 surf 函数,MATLAB 会抛出一个异常。如果你捕获这个异常,就能够看到 MException 对象结构的四个属性。

try
    surf
catch ME
    ME
end

 结果:

ME = 
  MException with properties:

    identifier: 'MATLAB:narginchk:notEnoughInputs'
       message: 'Not enough input arguments.'
         cause: {}
         stack: [1×1 struct]

 stack 字段显示抛出异常的文件名,函数和行号:

ans = 
  struct with fields:

    file: 'D:\Matlab 2017b\toolbox\matlab\graph3d\surf.m'
    name: 'surf'
    line: 49

在这种情况下,cause 字段为空。 

消息标识符

消息标识符是附加到错误或警告语句的标记,该错误或警告语句使得在 MATLAB 可以被唯一识别。你可以使用带有错误报告的消息标识符来更好地识别错误的来源,或者使用警告来控制程序中任何选定的警告子集。

消息标识符是只读字符向量,用于指定错误或警告的 component  和 mnemonic 标签。简单标识符的格式是

component:mnemonic

component 和 mnemonic之间用冒号分隔。如果标识符使用多个 component ,则需要多个冒号来分隔。消息标识符包含至少一个冒号。

消息标识符示例:

MATLAB:rmpath:DirNotFound
MATLAB:odearguments:InconsistentDataType
Simulink:actionNotTaken
TechCorp:OpenFile:notFoundInPath

component 和 mnemonic 字段都必须遵循以下语法规则:

标识符中的任何位置都不允许使用空格(空格或制表符)。

第一个字符必须是字母,不论大写或小写。

其余字符可以是字母数字或下划线。

component 和 mnemonic 没有长度限制。标识符也可以是空字符向量。

component 字段

component 字段指定了一个广泛的类别,在该类别下可以生成各种错误和警告。常用组件是特定产品或工具箱名称,例如MATLAB 或 Control,或者公司的名称,例如前面示例中的TechCorp。

还可以使用此字段指定多级组件。以下语句包含一个三级组件,后跟一个助记符标签:

TechCorp:TestEquipDiv:Waveform:obsoleteSyntax

组件字段可以保证每个标识符的唯一性。因此,虽然内部 MATLAB 代码可能使用某个警告标识符,如 MATLAB:InconsistentDataType,但这并不妨碍相同的助记符的使用,只要在其前面加上唯一的组件即可。例如,

warning('TechCorp:InconsistentDataType', ...
   'Value %s is inconsistent with existing properties.' ...
   sprocketDiam)


Mnemonic 字段

mnemonic 字段通常用作与特定消息相关的标签。例如,在报告由于使用模糊语法而导致的错误时,可能需要使用以下简单组件和助记符:

MATLAB:ambiguousSyntax

MException 对象中的消息标识符

抛出异常时,创建一个适当的标识符,并在使用以下语法构造对象时将其保存到 MException 对象

ME = MException(identifier, text)

示例:

ME = MException('AcctError:NoClient', ...
      'Client name not recognized.');

ME.identifier
ans =
    AcctError:NoClient

响应异常时,可以从 MException 对象中提取消息标识符,如下所示。

try
    surf
catch ME
    id = ME.identifier
end

id =
    MATLAB:narginchk:notEnoughInputs

 

错误消息的文本

MATLAB 中的错误消息是由程序代码发出并在 MException 对象中返回的只读字符向量。 该消息可以帮助用户确定故障的原因以及可能的补救措施。

抛出异常时,添加相应的错误消息并在使用语法构造对象时将其保存到MException对象。

ME = MException(identifier, text)

如果消息需要格式化规范(如 sprintf 函数),可以将此语法用于 MException 构造函数:

ME = MException(identifier,formatstring,arg1,arg2,...)

示例

S = 'Accounts';  f1 = 'ClientName';
ME = MException('AcctError:Incomplete', ...
      'Field ''%s.%s'' is not defined.', S, f1);
ME.message

结果

ans =
    Field 'Accounts.ClientName' is not defined.

响应异常时,可以从 MException 对象中提取错误消息,如下所示:

示例

try
    surf
catch ME
    msg = ME.message
end

结果 

msg =
    Not enough input arguments.

调用堆栈

MException 对象的堆栈字段标识检测到错误的行号,函数和文件名。 如果在被调用函数中发生错误,如下例所示,堆栈字段不仅包含当前错误的行号,函数名和文件名,还包含每个调用函数的行号,函数名和文件名。 在这种情况下,堆栈是 Nx1 数组,其中 N 表示调用堆栈的深度。 也就是说,堆栈字段显示发生异常的函数名称和行号,调用者的名称和行号,调用者的调用者等,直到达到最顶层的函数。

抛出异常时,MATLAB 将堆栈信息存储在堆栈字段中。 不过该字段是只读的。

例如,假设您有三个函数驻留在两个单独的文件中:

mfileA.m
=========================
        .
        .
42 function A1(x, y)
43 B1(x, y);



 mfileB.m
=========================
        .
        .
 8 function B1(x, y)
 9 B2(x, y)
        .
        .
26 function B2(x, y)
27      .
28      .
29      .
30      .
31 %  Throw exception here

在变量 ME 中捕获异常,然后检查堆栈字段:

for k=1:length(ME.stack)
    ME.stack(k)
end

结果

ans = 
    file: 'C:\matlab\test\mfileB.m'
    name: 'B2'
    line: 31
ans = 
    file: 'C:\matlab\test\mfileB.m'
    name: 'B1'
    line: 9
ans = 
    file: 'C:\matlab\test\mfileA.m'
    name: 'A1'
    line: 43

cause 数组

在某些情况下,不仅要记录有关导致程序停止的命令,还要记录代码捕获的其它异常信息。 你可以将这些额外的 MException 对象保存在主要异常的 cause 字段中。

MException 的 cause 字段是相关 MException 对象的可选胞元数组。 将对象添加到原因单元数组时,必须使用以下语法:

primaryException = addCause(primaryException, secondaryException)

此示例尝试将数组 D 分配给变量 X。如果 D 数组不存在,则代码尝试从 MAT 文件加载它,然后重试将其分配给 X。如果加载失败,则新的 MException 对象(ME3) 构造用于存储前两个错误(ME1 和 ME2)的原因:

try
    X = D(1:25)
catch ME1
    try
        filename = 'test200';
        load(filename);
        X = D(1:25)
    catch ME2
        ME3 = MException('MATLAB:LoadErr', ...
               'Unable to load from file %s', filename);
        ME3 = addCause(ME3, ME1);
        ME3 = addCause(ME3, ME2);
    end
end

此时,在 ME3 的 cause 字段中就有了两个异常:

ME3.cause
ans = 
    [1x1 MException]
    [1x1 MException]

检查 ME3 的 cause 字段:

ME3.cause{:}
ans =

	MException object with properties:

    identifier: 'MATLAB:UndefinedFunction'
       message: 'Undefined function or method 'D' for input 
arguments of type 'double'.'
         stack: [0x1 struct]
         cause: {}
ans =

	MException object with properties:

    identifier: 'MATLAB:load:couldNotReadFile'
       message: 'Unable to read file test204: No such file or 
directory.'
         stack: [0x1 struct]
         cause: {}

MException 类的方法

有十种方法可以与 MException 类一起使用。 这些方法的名称区分大小写。

MException.addCause将 MException 附加到另一个 MException 的 cause 字段
MException.getReport根据当前异常返回格式化消息
MException.last返回最后一次未捕获的异常(静态方法)
MException.rethrow重新发出先前捕获的异常
MException.throw发出异常
MException.throwAsCaller发出异常,但忽略堆栈字段中的当前堆栈帧

参考资料:

1.MATLAB 官方文档:https://ww2.mathworks.cn/help/ 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值