Erlang异常处理 #
一、异常概述 #
Erlang有三种异常类型:
| 类型 | 说明 | 触发方式 |
|---|---|---|
error |
运行时错误 | erlang:error/1 |
exit |
进程退出 | exit/1 |
throw |
抛出异常 | throw/1 |
二、try-catch表达式 #
2.1 基本语法 #
erlang
-module(try_basic).
-export([demo/1]).
demo(X) ->
try dangerous_operation(X) of
Result -> {ok, Result}
catch
error:Reason -> {error, Reason};
exit:Reason -> {exit, Reason};
throw:Reason -> {throw, Reason}
end.
dangerous_operation(0) -> erlang:error(zero_not_allowed);
dangerous_operation(N) when N < 0 -> exit(negative_value);
dangerous_operation(N) when N > 100 -> throw(too_large);
dangerous_operation(N) -> N * 2.
2.2 简化语法 #
erlang
-module(try_simple).
-export([safe_divide/2]).
safe_divide(A, B) ->
try A / B
catch
error:badarith -> {error, division_by_zero}
end.
2.3 after子句 #
erlang
-module(try_after).
-export([with_resource/1]).
with_resource(Resource) ->
try
use_resource(Resource)
after
release_resource(Resource)
end.
use_resource(R) -> {used, R}.
release_resource(R) -> io:format("Released: ~p~n", [R]).
2.4 完整语法 #
erlang
-module(try_complete).
-export([process/1]).
process(Data) ->
try
validate(Data),
transform(Data)
of
Result -> {ok, Result}
catch
error:validation_error -> {error, invalid_data};
error:Reason -> {error, Reason};
throw:Reason -> {thrown, Reason}
after
cleanup()
end.
validate(_) -> ok.
transform(D) -> {transformed, D}.
cleanup() -> ok.
三、异常类型 #
3.1 error #
erlang
-module(error_type).
-export([demo/0]).
demo() ->
try
erlang:error(my_error)
catch
error:Reason -> {caught_error, Reason}
end.
内置错误类型:
| 错误 | 说明 |
|---|---|
badarg |
错误参数 |
badarith |
算术错误 |
badmatch |
匹配失败 |
function_clause |
函数子句不匹配 |
case_clause |
case子句不匹配 |
if_clause |
if子句不匹配 |
undef |
函数未定义 |
badfun |
错误函数 |
badarity |
参数个数错误 |
3.2 exit #
erlang
-module(exit_type).
-export([demo/0]).
demo() ->
try
exit(my_exit)
catch
exit:Reason -> {caught_exit, Reason}
end.
3.3 throw #
erlang
-module(throw_type).
-export([demo/0]).
demo() ->
try
throw(my_throw)
catch
throw:Reason -> {caught_throw, Reason}
end.
3.4 捕获所有异常 #
erlang
-module(catch_all).
-export([demo/1]).
demo(Fun) ->
try Fun()
catch
_:_ -> caught_something
end.
四、捕获栈跟踪 #
4.1 获取栈跟踪 #
erlang
-module(stacktrace).
-export([demo/0]).
demo() ->
try
erlang:error(some_error)
catch
error:Reason:Stacktrace ->
io:format("Error: ~p~n", [Reason]),
io:format("Stacktrace: ~p~n", [Stacktrace])
end.
4.2 格式化栈跟踪 #
erlang
-module(format_stacktrace).
-export([demo/0]).
demo() ->
try
level1()
catch
error:Reason:Stacktrace ->
io:format("Error: ~p~n", [Reason]),
print_stacktrace(Stacktrace)
end.
level1() -> level2().
level2() -> level3().
level3() -> erlang:error(deep_error).
print_stacktrace(Stacktrace) ->
lists:foreach(
fun({Module, Function, Arity, Location}) ->
File = proplists:get_value(file, Location, "unknown"),
Line = proplists:get_value(line, Location, 0),
io:format(" ~p:~p/~p at ~s:~p~n", [Module, Function, Arity, File, Line])
end,
Stacktrace
).
五、catch表达式 #
5.1 基本catch #
erlang
-module(catch_expr).
-export([demo/0]).
demo() ->
Result = catch 1 / 0,
io:format("Result: ~p~n", [Result]).
5.2 catch vs try-catch #
erlang
-module(catch_vs_try).
-export([with_catch/1, with_try/1]).
with_catch(Fun) ->
case catch Fun() of
{'EXIT', Reason} -> {error, Reason};
Result -> {ok, Result}
end.
with_try(Fun) ->
try Fun()
catch
_:_ -> error
end.
建议:优先使用try-catch,更清晰易读。
六、错误处理模式 #
6.1 防御式编程 #
erlang
-module(defensive).
-export([safe_divide/2, safe_head/1, safe_nth/2]).
safe_divide(_, 0) -> {error, division_by_zero};
safe_divide(A, B) -> {ok, A / B}.
safe_head([]) -> {error, empty_list};
safe_head([H | _]) -> {ok, H}.
safe_nth(N, List) when N > 0, N =< length(List) ->
{ok, lists:nth(N, List)};
safe_nth(_, _) -> {error, index_out_of_bounds}.
6.2 Let it crash #
erlang
-module(let_it_crash).
-export([process/1]).
process(Data) ->
Result = dangerous_operation(Data),
handle_result(Result).
dangerous_operation(Data) -> Data.
handle_result(Result) -> Result.
6.3 监督模式 #
erlang
-module(supervised).
-export([run/1]).
run(Fun) ->
Pid = spawn_link(fun() -> worker(Fun) end),
monitor_worker(Pid).
worker(Fun) ->
try Fun()
catch
_:_ -> ok
end.
monitor_worker(Pid) ->
receive
{'EXIT', Pid, normal} -> ok;
{'EXIT', Pid, Reason} -> {error, Reason}
end.
七、实际应用 #
7.1 文件操作 #
erlang
-module(file_ops).
-export([read_file/1, write_file/2]).
read_file(Path) ->
try
{ok, Binary} = file:read_file(Path),
{ok, Binary}
catch
error:{badmatch, {error, Reason}} -> {error, Reason}
end.
write_file(Path, Content) ->
try
ok = file:write_file(Path, Content),
ok
catch
error:{badmatch, {error, Reason}} -> {error, Reason}
end.
7.2 JSON解析 #
erlang
-module(json_parse).
-export([parse/1]).
parse(Binary) ->
try
{ok, Term} = decode_json(Binary),
{ok, Term}
catch
error:{badmatch, error} -> {error, invalid_json};
error:Reason -> {error, Reason}
end.
decode_json(<<"null">>) -> {ok, null};
decode_json(<<"true">>) -> {ok, true};
decode_json(<<"false">>) -> {ok, false};
decode_json(Num) when is_binary(Num) ->
case string:to_float(binary_to_list(Num)) of
{Float, _} -> {ok, Float};
{error, _} ->
case string:to_integer(binary_to_list(Num)) of
{Int, _} -> {ok, Int};
error -> error
end
end.
7.3 HTTP请求 #
erlang
-module(http_request).
-export([get/1, post/2]).
get(Url) ->
try
{ok, {{_, Status, _}, _Headers, Body}} =
httpc:request(get, {Url, []}, [], [{body_format, binary}]),
{ok, Status, Body}
catch
error:{badmatch, {error, Reason}} -> {error, Reason};
error:Reason -> {error, Reason}
end.
post(Url, Data) ->
try
{ok, {{_, Status, _}, _Headers, Body}} =
httpc:request(post, {Url, [], "application/json", Data}, [], [{body_format, binary}]),
{ok, Status, Body}
catch
error:{badmatch, {error, Reason}} -> {error, Reason};
error:Reason -> {error, Reason}
end.
7.4 数据库操作 #
erlang
-module(db_ops).
-export([with_connection/2]).
with_connection(Conn, Fun) ->
try
Result = Fun(Conn),
{ok, Result}
catch
error:Reason ->
rollback(Conn),
{error, Reason}
after
return_connection(Conn)
end.
rollback(_Conn) -> ok.
return_connection(_Conn) -> ok.
八、错误处理最佳实践 #
8.1 明确错误类型 #
erlang
-module(error_types).
-export([process/1]).
process(Data) ->
case validate(Data) of
{ok, ValidData} ->
try
Result = transform(ValidData),
{ok, Result}
catch
error:Reason -> {error, {transform_error, Reason}}
end;
{error, Reason} ->
{error, {validation_error, Reason}}
end.
validate(_) -> {ok, valid}.
transform(D) -> D.
8.2 不要过度捕获 #
erlang
-module(over_catch).
-export([bad/1, good/1]).
bad(Fun) ->
try Fun()
catch
_:_ -> ok
end.
good(Fun) ->
try Fun()
catch
error:Reason -> {error, Reason}
end.
8.3 使用after清理 #
erlang
-module(cleanup).
-export([with_file/2]).
with_file(Path, Fun) ->
{ok, File} = file:open(Path, [read]),
try
Fun(File)
after
file:close(File)
end.
8.4 记录错误 #
erlang
-module(error_logging).
-export([process/1]).
process(Data) ->
try
dangerous_operation(Data)
catch
error:Reason:Stacktrace ->
logger:error("Error processing data: ~p~nStacktrace: ~p~n",
[Reason, Stacktrace]),
{error, Reason}
end.
dangerous_operation(D) -> D.
九、总结 #
本章学习了:
- 异常类型:error、exit、throw
- try-catch表达式
- 栈跟踪捕获
- catch表达式
- 错误处理模式
- 实际应用案例
- 最佳实践
准备好学习函数了吗?让我们进入下一章。
最后更新:2026-03-27