5.4.2 异常捕捉
在异常发生时,throw()抛出错误后,需要对其进行捕捉才能在恰当的位置有针对性地进行处置。在Julia提供的捕捉机制中,将可疑语句放在try和end组成的异常处理结构中,如下所示:
try # 正常语句块 catch 异常类型变量 # 异常处理语句块 finally # 收尾清理语句块 end
其中,try和end是必需的,两者之间的语句块便是预期正常运行的业务代码,可视为复合表达式;catch是异常捕捉语句,其后一般会跟着一个“异常类型变量”,用于提取try中发生之的异常类型,可针对异常类型变量的不同情况进行异常处置;而finally中的语句块用于清理收尾,该部分的代码无论是否发生异常,都会执行。
在异常捕捉结构中,除了try和end必需外,catch和finally两者也必须至少提供一个。下面给出一个的例子:
julia> try log(-10) catch ex tuprintln("exception type: ", ex) finally println("here is finally") end exception type: DomainError(:log, "-10.0 will only return a complex result if called with a complex argument. Try -10.0(Complex(x)).") here is finally
其中,log()函数要求参数必须是正数,但提供的参数却是负数,所以会报错。运行中,异常发生时,类型DomainError()被记录在了变量ex中。再例如:
julia> except_test(x) = try if 1 == x log(-10) else x[2] end catch ex if isa(ex, DomainError) # 针对不同的类型做不同的处理 println("Catched DomainError") elseif isa(ex, BoundsError) println("Catched BoundsError") end end except_test (generic function with 1 method) julia> except_test(1) Catched DomainError julia> except_test(0) Catched BoundsError
在异常处理的语法结构中,finally在对文件、网络等资源操作时比较有用。因为无论try代码块是否正常执行,还是catch代码块是否恰当地处理了异常,finally中的代码块都会执行,所以常用来关闭并释放各种资源,进行各种清理工作。例如:
julia> f = open("file"); julia> try # 对文件对象f进行处理 catch ex # 异常处理 finally close(f) # 关闭文件对象 end
上例中,无论try是否顺利地对f进行了处理,close(f)都会执行。期间,若确实发生了异常,则先执行catch中的逻辑,然后也会自动流转到finally中。
在Julia的异常处理语法中,如果出现无法正确处理的错误,则可以通过rethrow()函数、backtrace()函数或catch_backtrace()函数对发现的异常再次传播,留给外部的代码进行处置,或者通过嵌套的try语法结构进行更深层的处理。
虽然异常机制为代码的健壮性提供了一层保障,但异常处理机制不能当成一种特效药,更不能成为依赖。最好的防范措施是充分地测试,避免可能错误的出现。