第四章 异常
Table of Contents
第四章 异常
4.1 异常
Erlang通过throw(Exception)、exit(Exception)、erlang:error(Exception)来抛出异常。
Erlang捕获异常的两种方式:
- 使用try…catch表达式将函数括起来(同java)
- 把函数调用包含在catch表达式中
4.2 抛出异常
- exit(Why)
- 显式的产生错误
- throw(Why)
- 抛出调用者可能会捕获的异常(同java)
- erlang:error(Why)
- 系统级错误
4.3 try…catch
try…catch的语法结构:
%% 首先对FuncOrExpressionSequence求值 %% 如果没有产生异常则顺序进行Patterm匹配, 匹配成功后执行后面的表达式 %% 如果有异常抛出, 则顺序匹配ExPattern(ExceptionType是throw、exit、error中的一个, 默认为throw) %% after块中的代码用于清理工作, 同java异常捕获时的finally try FuncOrExpressionSequence of Pattern1 [when Guard1] ->Expressions1; Pattern2 [when Guard2] ->Expressions2; ... catch ExceptionType: ExPattern1 [when ExGuard1] ->ExExpressions1; ExceptionType: ExPattern2 [when ExGuard2] ->ExExpressions2; ... after AfterExpressions end.
其相当于在尾部带有catch和after块的case表达式。
4.3.1 缩减版本
%% 省略掉after块 try F catch ... end.
4.3.2 使用try…catch的编程惯例
%% 将三种异常方式依次捕获 try F catch throw: X ->ExExpressions1; exit: X ->ExExpressions2; error: X ->ExExpressions3 end.
4.4 catch
使用catch原语捕获异常, 返回的描述错误的元组可以提供更详细的信息。
4.5 改进错误信息
使用erlang:error处理函数的异常参数, 可以获取更清晰的错误信息。
4.6 try…catch的编程风格
4.6.1 经常会返回错误的程序
%% 可以针对两种可能的返回值分别处理 case f(X) of {ok, Val} ->Expressions1; {error, Why} ->Expressions2 end. %% 也可以只处理正常返回, 而对非正常返回抛出异常 {ok, Val} = f(X), Expressions1; ...
4.6.2 出错几率比较小的程序
检测异常的代码分支应与函数中异常抛出的分支互相匹配。
%% 函数中抛出异常的分支 f(X) -> case ... of ... -> ... throw({thisError, ...}) ... -> ... throw({someOtherError, ...}) %% 检测异常的代码分支 try f(X) catch throw:{thisError, X} ->... throw:{someOtherError, X} ->... end.
4.7 捕获所有可能的异常
%% 使用通配符'_'来匹配异常类型(throw,exit,error)和异常值 try Expr catch _:_ ->... end.
4.8 新老两种异常处理风格
%% 旧的风格 case (catch foo(...)) of {'EXIT', Why} ->... Val ->... end. %% 新的风格 try foo(...) of Val ->... catch exit: Why ->... end.
4.9 栈跟踪
erlang:get_stacktrace()可以查看栈跟踪信息, 即如果调用不发生异常那么这些信息中就包括了函数的调用路径。