Julia语言程序设计
上QQ阅读APP看书,第一时间看更新

5.4.1 异常触发

由于程序设计时,每段代码的正确执行都需要特定的前置条件,而通常这些条件是可知的。一旦条件不满足,会导致后续主要逻辑的不正常或无法运行,为此可以对这些可预知的“错误”进行提前设定处置逻辑,这些分支逻辑即是异常处理逻辑。

另外,既然是可知的错误,就可以预先对某些常见的错误进行定义,以便于后续的跟踪与处置。Julia中内置定义了很多错误类型,均继承自抽象类型Exception。本书在附录A中列出了常见的异常类型,更多的可参见官方文档。

对于这些预定义的错误,可在需要的时候通过throw()函数显式地抛出,以上报该处代码发生的问题,并方便后续的调试与处置。

例如有一个函数只能处理非负数,却收到了负数参数,如下所示:


julia> f(x) = x>=0 ? exp(-x) : throw(DomainError("x<0")) # 当x<0时抛出DomainError异常
f (generic function with 1 method)

julia> f(1)
0.36787944117144233

julia> f(-1)                                                                                        # 负数作为参数
ERROR: DomainError with x<0:

Stacktrace:
  [1] f(::Int64) at .\REPL[1]:1
  [2] top-level scope at none:0

可见一旦运行条件不符合要求,DomainError的实例便会被抛出,同时会传递关于异常的描述信息。

提示 在异常信息之后,同时会有Stacktrace字段给出错误发生的具体函数原型及其定义的位置。因为该字段主要提示错误发生的位置,所以每次原型都会有所差异,本书因为篇幅,在下面的示例中出现错误时会省略该字段,仅展示ERROR信息。

除了预定义的错误类型,还有一个通用的异常类型ErrorException,能够在上报时以简短的信息描述错误的情况。若是希望自定义异常类型,则可声明Exception新的子类型,此后便可通过函数throw()在需要的时候上报新声明的错误类型,以便进行恰当的处置。

若无须针对错误的类型进行后续处理,而仅需对错误进行提示,则可直接通过@error宏上报。例如:


julia> fussy_sqrt(x) = x >= 0 ? sqrt(x) : @error "negative x not allowed"
fussy_sqrt (generic function with 1 method)

julia> fussy_sqrt(2)
1.4142135623730951

julia> fussy_sqrt(-1)
┌ Error: negative x not allowed         # 在REPL中Error会以红色显示
└ @ Main REPL[36]:1

这其实并非属于异常类型机制中的内容,而是开发中最为常用的日志工具,也是发现问题最为简单有效的手段。

与@error类似的还有@info,@warn和@debug,分属于不同的日志级别,依次为常规信息、警告信息及调试信息。当然,它们打印的信息前缀是有所区别的,例如:


julia> @info "information message"
[ Info: information message

julia> @warn "warning message"
┌ Warning: warning message
└ @ Main REPL[40]:1

关于日志方面,Julia有一个Logging包,提供了更为全面的功能,开发者可以根据需要安装使用。通过在代码恰当的位置输出对应的信息,能够在程序的编写、调试及测试方面带来很大的帮助。