📜  Julia 中的异常处理

📅  最后修改于: 2021-11-25 04:47:30             🧑  作者: Mango

正常程序执行期间发生的任何意外情况都称为异常。 Julia 中的异常处理是一种机制,可以通过确定一条替代路径来继续正常程序执行来克服这种情况。如果异常没有得到处理,程序会突然终止。程序不知道发生异常时要执行的操作。避免编译器在此类异常上崩溃的过程称为异常处理。

异常处理

Julia 允许通过使用 try-catch 块进行异常处理。可能抛出异常的代码块放在 try 块中,catch 块处理抛出的异常。异常通过调用堆栈传播,直到找到 try-catch 块。让我们考虑下面的代码,在这里我们尝试找到抛出“DomainError”并且程序终止的 -1 的平方根。

println(sqrt(-1))

输出:

ERROR: LoadError: DomainError:
sqrt will only return a complex result if called with a complex argument. Try sqrt(complex(x)).
Stacktrace:
 [1] sqrt(::Int64) at ./math.jl:434
while loading /home/cg/root/945981/main.jl, in expression starting on line 1

如果没有 try-catch 块,程序会突然终止。但是,我们可以通过使用 try-catch 块优雅地处理异常来防止程序终止。

println("Before Exception")
try
    sqrt(-1)
catch
    println("Cannot find the square root of negative numbers")
end
println("After Exception")

输出:

Before Exception
Cannot find the square root of negative numbers
After Exception

try-catch 块还允许将异常存储在变量中。使用catch块处理多种异常的方法称为Canonical方法。如果 x 可索引,以下示例计算 x 的第三个元素的平方根,否则假定 x 是实数并返回其平方根。

sqrt_third(x) = try
        println(sqrt(x[3]))
    catch y
        if isa(y, DomainError)
            println(sqrt(complex(x[3], 0)))
        elseif isa(y, BoundsError)
            println(sqrt(x))
        end
    end
  
  
sqrt_third([1 9 16 25])
sqrt_third([1 -4 9 16])
sqrt_third(25)
sqrt_third(-9)

输出:

4.0
3.0
5.0
ERROR: LoadError: DomainError:
Stacktrace:
 [1] sqrt_third(::Int64) at /home/cg/root/945981/main.jl:7
while loading /home/cg/root/945981/main.jl, in expression starting on line 15

finally 子句的使用

无论是否发生异常,finally 块都会运行。 finally 块中的代码可用于关闭资源,如打开的文件或其他清理工作。

try
    f = open("file.txt")
catch
    println("No such file exists")
finally
    println("After exception")
end

输出:

No such file exists
After exception

抛出异常

throw()函数可用于抛出自定义异常。以下示例显示从函数抛出并由 catch 块处理的错误。 error()函数用于产生一个 ErrorException。

function f(x)
    if(x < 5)
        throw(error())
    end
    return sqrt(x)
end
  
try
    println(f(9))
    println(f(1))
catch e
    println("Argument less than 5")
end

输出:

3.0
Argument less than 5

异常也可以从 catch 块中抛出。 catch 块可能包含一些代码来处理捕获的异常,然后重新抛出异常。此异常必须由同一方法中的另一个 try-catch 块或调用堆栈中的任何其他方法处理。如果未捕获异常,则异常会一直传播到主函数。

function f(x)
    if(x < 5)
        throw(error())
    end
    return sqrt(x)
end
  
try
    println(f(9))
    println(f(1))
catch e
    println("Argument less than 5")
    throw(error())
end

输出:

3.0
Argument less than 5
ERROR: LoadError: 
Stacktrace:
 [1] error() at ./error.jl:30
while loading /home/cg/root/945981/main.jl, in expression starting on line 13

从 catch 块抛出错误

function f(x)
    if(x < 5)
        throw(error())
    end
    return sqrt(x)
end
  
try
    try
        println(f(9))
        println(f(1))
    catch e
        println("Argument less than 5")
        throw(error())
    end
catch e
    println("Second catch block")
end

输出:

3.0
Argument less than 5
Second catch block

一行尝试捕获

try sqrt(x) catch y end

这意味着尝试 sqrt(x),如果抛出异常,则将其传递给变量 y。
现在如果必须返回存储在 y 中的值,那么 catch 后面必须跟一个分号。

try sqrt(x) catch; y end
try println(sqrt(-9)) catch; y end

输出:

ERROR: LoadError: UndefVarError: y not defined
while loading /home/cg/root/945981/main.jl, in expression starting on line 1

内置异常

Julia 提供了一些内置的异常,如下所示:

Exception Description
ArgumentError This exception is thrown when the parameters to a function call do not match a valid signature.
BoundsError This exception is thrown if there the user tries to access anarray index beyond the index range.
CompositeException This exception provides information about each subtask that throws exception within a task.
DimensionMismatch This exception is thrown when objects called do not have matching dimensionality.
DivideError This exception is thrown when the user tries to divide by 0(zero).
DomainError This exception is thrown when the argument to a function or constructor does not lie in the valid domain.
EOFError This exception is thrown when there is no more data left to read in a file.
ErrorException This exception is thrown to indicate generic error.
InexactError This exception is thrown when the program cannot exactly convert a particular value to type T in a method.
InitError This exception is thrown when an error occurs while running __init__ function of a module.
InterruptException This exception is thrown when a process is stopped from the terminal using CTRL+C .
InvalidStateException This exception is thrown when the program runs into an invalid state.
KeyError This exception is thrown when when a user tries to access or delete a non-existing element from AbstractDict or Set.
LoadError This exception is thrown if an error occurs while importing or using a file.
OutOfMemoryError This exception is thrown when a program exceeds the available system memory.
ReadOnlyMemoryError This exception is thrown when a program tries to write a memory that is read-only.
RemoteException This exception is thrown when exception of a remote computer is thrown locally. The exception specifies the pid of the worker and the corresponding exception.
MethodError This exception is thrown when a method with the required type signature does not exist.
OverflowError This exception is thrown when result of an expression is too large for the specified type and causes a wrap-around.
Meta.ParseError This exception is thrown when an expression passed to the parse function cannot be interpreted as a valid Julia expression.
SystemError This exception is thrown when a system call fails.
TypeError This exception is thrown when a type assertion fails, or an intrinsic function is called with incorrect argument type.
UndefRefError This exception is thrown if an item or field is not defined for the specified object.
UndefVarError This exception is thrown when a symbol is not defined in the current scope.
StringIndexError This exception is thrown when the user tries to access a string index that exceeds the string length.