官术网_书友最值得收藏!

Exception handling

When executing a program, abnormal conditions can occur that force the Julia runtime to throw an exception or error, show the exception message and the line where it occurred, and then exit. For example (follow along with the code in Chapter 4\errors.jl):

  • Using the wrong index for an array, for example, arr = [1,2,3]and then asking for arr[0] causes a program to stop with ERROR: BoundsError()
  • Calling sqrt() on a negative value, for example, sqrt(-3) causes ERROR: DomainError: sqrt will only return a complex result if called with a complex argument, try sqrt(complex(x)); the sqrt(complex(-3)) function gives the correct result 0.0 + 1.7320508075688772im
  • A syntax error in Julia code will usually result in LoadError

Similar to these, there are 18 predefined exceptions that Julia can generate (refer to http://docs.julialang.org/en/latest/manual/control-flow/#man-exception-handling). They are all derived from a base type, Exception.

How can you signal an error condition yourself? You can call one of the built-in exceptions by throwing such an exception; that is, calling the throw function with the exception as an argument. Suppose an input field, code, can only accept the codes listed in codes = ["AO", "ZD", "SG", "EZ"]. If code has the value, AR, the following test produces DomainError:

if code in codes 
    println("This is an acceptable code") 
else 
    throw(DomainError()) 
end

A rethrow() statement can be useful to hand the current exception to a higher calling code level.

Note that you can't give your own message as an argument to DomainError(). This is possible with the error(message) function (refer to the Conditional evaluation section) with a String message. This results in a program stopping with an ErrorException function and an ERROR: message message.

Creating user-defined exceptions can be done by deriving from the base type, Exception, such as mutable struct CustomException <: Exception end (for an explanation of <, refer to the The type hierarchy - subtypes and supertypes section in Chapter 6, More on Types, Methods, and Modules). These can also be used as arguments to be thrown.

In order to catch and handle possible exceptions yourself so that the program can continue to run, Julia uses the familiar try...catch...finally construct, which includes the following:

  • The dangerous code that comes in the try block
  • The catch block that stops the exception and allows you to react to the code that threw the exception

Here is an example:

a = [] 
try 
    pop!(a) 
catch ex 
    println(typeof(ex))   
    showerror(STDOUT, ex) 
end 

This example prints the output, as follows:

 ArgumentError 
     array must be non-empty 

Popping an empty array generates an exception. The variable, ex, contains the exception object, but a plain catch without a variable can also be used. The showerror function is a handy function; its first argument can be any I/O stream, so it could be a file.

To differentiate between the different types of exception in the catch block, you can use the following code:

try  
  # try this code 
catch ex 
  if isa(ex, DomainError) 
    # do this 
  elseif isa(ex, BoundsError) 
    # do this 
  end 
end 

Similar to if and while, try is an expression, so you can assign its return value to a variable. So, run the following code:

ret = try 
           global a = 4 * 2 
      catch ex 
      end 

After running the preceding code, ret contains the value 8.

Sometimes, it is useful to have a set of statements to be executed no matter what, for example, to clean up resources. Typical use cases are when reading from a file or a database. We want the file or the database connection to be closed after the execution, regardless of whether an error occurred while the file or database was being processed. This is achieved with the finally clause of a try...catch...finally construct, as in the following code snippet:

try
   global f = open("file1.txt") # returns an IOStream(<file file1.txt>) 
# operate on file f 
catch ex 
finally 
    close(f) 
end 

f must be defined as global in try, otherwise it is not known in the finally branch.

Here is a more concrete example:

try
open("file1.txt", "r") do f
k = 0
while(!eof(f))
a=readline(f)
println(a)
k += 1
end
println("\nNumber of lines in file: $k")
end
catch ex
finally
close(f)
end

The try...catch...finally full construct guarantees that the finally block is always executed, even when there is a return in try. In general, all three combinations of try...catch, try...finally, and try...catch...finally are possible.

It is important to realize that try...catch should not be used in performance bottlenecks, because the mechanism impedes performance. Whenever feasible, test a possible exception with normal conditional evaluation.

The preceding code can be written more idiomatically as follows:

open("file1.txt", "w") do f
# operate on file f
end

close(f) is no longer needed: it is done implicitly with the end.

主站蜘蛛池模板: 翁牛特旗| 乌什县| 保山市| 呼图壁县| 云浮市| 永善县| 玉环县| 逊克县| 株洲市| 桃园市| 潮州市| 民勤县| 石首市| 湟中县| 青州市| 乐业县| 静宁县| 栾城县| 尤溪县| 保康县| 阿坝县| 辛集市| 高淳县| 绍兴县| 九江县| 淮安市| 望谟县| 乐至县| 宣恩县| 盘锦市| 庄河市| 沙雅县| 盐亭县| 新巴尔虎左旗| 烟台市| 蒙自县| 扶沟县| 怀柔区| 明水县| 咸宁市| 衡山县|