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

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语法结构进行更深层的处理。

虽然异常机制为代码的健壮性提供了一层保障,但异常处理机制不能当成一种特效药,更不能成为依赖。最好的防范措施是充分地测试,避免可能错误的出现。