begin
# Some code which may cause an exception
rescue <Exception Class>
# Code to recover from the exception
end
例如 :
begin
x = 1/0
rescue Exception
x = 0
puts( $!.class )
puts( $! )
end
puts( x )
执行结果 :
ZeroDivisionError
divided by 0
0
class ZeroDivisionError def to_s return "you cann't divided by 0" end end begin x = 1/0 rescue Exception x = 0 puts( $!.class ) puts( $! ) end puts( x )
执行结果 :
ZeroDivisionError you cann't divided by 0 0
def calc( val1, val2 )
return val1 / val2
end
begin
result = calc(10,0)
rescue Exception => e1
puts(e1.class)
puts(e1)
result = 0
end
puts(result)
执行结果 :
ZeroDivisionError divided by 0 0
接下来我们来看看Exception的继承关系 :
def putclass(obj1) p(obj1.superclass) if obj1.superclass != nil then putclass(obj1.superclass) end end putclass(ZeroDivisionError)
输出结果 :
StandardError Exception Object BasicObject nil
def putclass(obj1)
p(obj1.superclass)
if obj1.superclass != nil then putclass(obj1.superclass) end
end
def calc( val1, val2 )
return val1 / val2
end
begin
result = calc("a",0)
rescue Exception => e1
puts(e1.class)
puts(e1)
result = 0
end
puts(result)
putclass(e1.class)
begin
result = calc(10,"a")
rescue Exception => e1
puts(e1.class)
puts(e1)
result = 0
end
puts(result)
putclass(e1.class)
输出结果 :
NoMethodError undefined method `/' for "a":String 0 NameError StandardError Exception Object BasicObject nil TypeError String can't be coerced into Fixnum 0 StandardError Exception Object BasicObject nil
def calc( val1, val2 ) begin result = val1 / val2 rescue TypeError, NoMethodError => e puts( e.class ) puts( e ) puts( "One of the values is not a number!" ) result = nil rescue Exception => e puts( e.class ) puts( e ) result = nil end return result end p calc("a",1)
执行结果 :
NoMethodError undefined method `/' for "a":String One of the values is not a number! nil
startdir = Dir.getwd
begin
Dir.chdir( "X:\\" ) # 假设这个目录不存在或为空
puts( `dir` )
rescue Exception => e
puts e.class
puts e
ensure
Dir.chdir( startdir )
end
p startdir
p Dir.getwd
执行结果 :
Errno::ENOENT
No such file or directory - X:\
"C:/Users/digoal/Desktop"
"C:/Users/digoal/Desktop
"
再来测试一个,
# cat test.rb
#!/opt/ruby/bin/ruby
f = File.new( "text" )
begin
for i in (1..6) do
puts("line number: #{f.lineno}")
line = f.gets.chomp
num = line.to_i
puts( "Line '#{line}' is converted to #{num}" )
puts( 100 / num )
end
rescue Exception => e
puts( e.class )
puts( e )
ensure
f.close
puts( "File closed" )
end
# text文件的最后一行是字符串, 无法转换为Fixnum, 因此会捕获到异常,
# 不管有没有异常我们都需要关闭这个文件. 因此ensure代码中写了f.close
# cat text
1
2
3
4
5
jd
执行结果 :
line number: 0
Line '1' is converted to 1
100
line number: 1
Line '2' is converted to 2
50
line number: 2
Line '3' is converted to 3
33
line number: 3
Line '4' is converted to 4
25
line number: 4
Line '5' is converted to 5
20
line number: 5
Line 'jd' is converted to 0
ZeroDivisionError
divided by 0
File closed
begin
# code which may cause an exception
rescue [Exception Type]
else # optional section executes if no exception occurs
ensure # optional exception always executes
end
例如 :
def doCalc( aNum )
begin
result = 100 / aNum.to_i
rescue Exception => e # executes when there is an error
result = 0
msg = "Error: " + e.to_s
else # executes when there is no error
msg = "Result = #{result}"
ensure # always executes
msg = "You entered '#{aNum}'. " + msg
end
return msg
end
p doCalc("a")
p doCalc(1)
执行结果 :
"You entered 'a'. Error: divided by 0"
"You entered '1'. Result = 100"
def showFamily( aClass )
if (aClass != nil) then
puts( "#{aClass} :: about to recurse with aClass.superclass = #{aClass.superclass.inspect}" )
showFamily( aClass.superclass )
end
end
def chDisk( aChar )
startdir = Dir.getwd
begin
Dir.chdir( "#{aChar}:\\" )
puts( `dir` )
rescue Exception => e
showFamily( e.class ) # to see ancestors, uncomment
puts e.class # ...and comment out this
puts e
ensure
Dir.chdir( startdir )
end
end
chDisk( "F" ) # F是我的光驱, 没放光盘,
chDisk( "X" ) # X是一个不存在的盘,
chDisk( "ABC" ) # ABC则是一个格式错误的盘符.
执行结果 :
Errno::EACCES :: about to recurse with aClass.superclass = SystemCallError
SystemCallError :: about to recurse with aClass.superclass = StandardError
StandardError :: about to recurse with aClass.superclass = Exception
Exception :: about to recurse with aClass.superclass = Object
Object :: about to recurse with aClass.superclass = BasicObject
BasicObject :: about to recurse with aClass.superclass = nil
Errno::EACCES
Permission denied - F:\
Errno::ENOENT :: about to recurse with aClass.superclass = SystemCallError
SystemCallError :: about to recurse with aClass.superclass = StandardError
StandardError :: about to recurse with aClass.superclass = Exception
Exception :: about to recurse with aClass.superclass = Object
Object :: about to recurse with aClass.superclass = BasicObject
BasicObject :: about to recurse with aClass.superclass = nil
Errno::ENOENT
No such file or directory - X:\
Errno::EINVAL :: about to recurse with aClass.superclass = SystemCallError
SystemCallError :: about to recurse with aClass.superclass = StandardError
StandardError :: about to recurse with aClass.superclass = Exception
Exception :: about to recurse with aClass.superclass = Object
Object :: about to recurse with aClass.superclass = BasicObject
BasicObject :: about to recurse with aClass.superclass = nil
Errno::EINVAL
Invalid argument - ABC:\
Ruby exception objects are subclasses of Exception. However, operating systems typically report errors using plain integers. Module Errno is created dynamically to map these operating system errors to Ruby classes, with each error number generating its own subclass of SystemCallError. As the subclass is created in module Errno, its name will start Errno::.
The names of the Errno:: classes depend on the environment in which Ruby runs. On a typical Unix or Windows platform, there are Errno classes such as Errno::EACCES, Errno::EAGAIN, Errno::EINTR, and so on.
The integer operating system error number corresponding to a particular error is available as the class constantErrno::error::Errno.
Errno::EACCES::Errno #=> 13 Errno::EAGAIN::Errno #=> 11 Errno::EINTR::Errno #=> 4
The full list of operating system errors on your particular platform are available as the constants of Errno.
Errno.constants #=> :E2BIG, :EACCES, :EADDRINUSE, :EADDRNOTAVAIL, ...
p Errno.constants.sort
[:E2BIG, :EACCES, :EADDRINUSE, :EADDRNOTAVAIL, :EADV, :EAFNOSUPPORT, :EAGAIN, :EALREADY, :EAUTH, :EBADE, :EBADF, :EBADFD, :EBADMSG, :EBADR, :EBADRPC, :EBADRQC, :EBADSLT, :EBFONT, :EBUSY, :ECANCELED, :ECHILD, :ECHRNG, :ECOMM, :ECONNABORTED, :ECONNREFUSED, :ECONNRESET, :EDEADLK, :EDEADLOCK, :EDESTADDRREQ, :EDOM, :EDOOFUS, :EDOTDOT, :EDQUOT, :EEXIST, :EFAULT, :EFBIG, :EFTYPE, :EHOSTDOWN, :EHOSTUNREACH, :EIDRM, :EILSEQ, :EINPROGRESS, :EINTR, :EINVAL, :EIO, :EIPSEC, :EISCONN, :EISDIR, :EISNAM, :EKEYEXPIRED, :EKEYREJECTED, :EKEYREVOKED, :EL2HLT, :EL2NSYNC, :EL3HLT, :EL3RST, :ELIBACC, :ELIBBAD, :ELIBEXEC, :ELIBMAX, :ELIBSCN, :ELNRNG, :ELOOP, :EMEDIUMTYPE, :EMFILE, :EMLINK, :EMSGSIZE, :EMULTIHOP, :ENAMETOOLONG, :ENAVAIL, :ENEEDAUTH, :ENETDOWN, :ENETRESET, :ENETUNREACH, :ENFILE, :ENOANO, :ENOATTR, :ENOBUFS, :ENOCSI, :ENODATA, :ENODEV, :ENOENT, :ENOEXEC, :ENOKEY, :ENOLCK, :ENOLINK, :ENOMEDIUM, :ENOMEM, :ENOMSG, :ENONET, :ENOPKG, :ENOPROTOOPT, :ENOSPC, :ENOSR, :ENOSTR, :ENOSYS, :ENOTBLK, :ENOTCONN, :ENOTDIR, :ENOTEMPTY, :ENOTNAM, :ENOTRECOVERABLE, :ENOTSOCK, :ENOTSUP, :ENOTTY, :ENOTUNIQ, :ENXIO, :EOPNOTSUPP, :EOVERFLOW, :EOWNERDEAD, :EPERM, :EPFNOSUPPORT, :EPIPE, :EPROCLIM, :EPROCUNAVAIL, :EPROGMISMATCH, :EPROGUNAVAIL, :EPROTO, :EPROTONOSUPPORT, :EPROTOTYPE, :ERANGE, :EREMCHG, :EREMOTE, :EREMOTEIO, :ERESTART, :ERFKILL, :EROFS, :ERPCMISMATCH, :ESHUTDOWN, :ESOCKTNOSUPPORT, :ESPIPE, :ESRCH, :ESRMNT, :ESTALE, :ESTRPIPE, :ETIME, :ETIMEDOUT, :ETOOMANYREFS, :ETXTBSY, :EUCLEAN, :EUNATCH, :EUSERS, :EWOULDBLOCK, :EXDEV, :EXFULL, :NOERROR]
查询Errno常量值 :
for err in Errno.constants.sort do
errnum = eval( "Errno::#{err}::Errno" )
print( "#{err} #{errnum} ," )
end
结果
E2BIG 7 ,EACCES 13 ,EADDRINUSE 10048 ,EADDRNOTAVAIL 10049 ,EADV 0 ,EAFNOSUPPORT 10047 ,EAGAIN 11 ,EALREADY 10037 ,EAUTH 0 ,EBADE 0 ,EBADF 9 ,EBADFD 0 ,EBADMSG 0 ,EBADR 0 ,EBADRPC 0 ,EBADRQC 0 ,EBADSLT 0 ,EBFONT 0 ,EBUSY 16 ,ECANCELED 0 ,ECHILD 10 ,ECHRNG 0 ,ECOMM 0 ,ECONNABORTED 10053 ,ECONNREFUSED 10061 ,ECONNRESET 10054 ,EDEADLK 36 ,EDEADLOCK 36 ,EDESTADDRREQ 10039 ,EDOM 33 ,EDOOFUS 0 ,EDOTDOT 0 ,EDQUOT 10069 ,EEXIST 17 ,EFAULT 14 ,EFBIG 27 ,EFTYPE 0 ,EHOSTDOWN 10064 ,EHOSTUNREACH 10065 ,EIDRM 0 ,EILSEQ 42 ,EINPROGRESS 10036 ,EINTR 4 ,EINVAL 22 ,EIO 5 ,EIPSEC 0 ,EISCONN 10056 ,EISDIR 21 ,EISNAM 0 ,EKEYEXPIRED 0 ,EKEYREJECTED 0 ,EKEYREVOKED 0 ,EL2HLT 0 ,EL2NSYNC 0 ,EL3HLT 0 ,EL3RST 0 ,ELIBACC 0 ,ELIBBAD 0 ,ELIBEXEC 0 ,ELIBMAX 0 ,ELIBSCN 0 ,ELNRNG 0 ,ELOOP 10062 ,EMEDIUMTYPE 0 ,EMFILE 24 ,EMLINK 31 ,EMSGSIZE 10040 ,EMULTIHOP 0 ,ENAMETOOLONG 38 ,ENAVAIL 0 ,ENEEDAUTH 0 ,ENETDOWN 10050 ,ENETRESET 10052 ,ENETUNREACH 10051 ,ENFILE 23 ,ENOANO 0 ,ENOATTR 0 ,ENOBUFS 10055 ,ENOCSI 0 ,ENODATA 0 ,ENODEV 19 ,ENOENT 2 ,ENOEXEC 8 ,ENOKEY 0 ,ENOLCK 39 ,ENOLINK 0 ,ENOMEDIUM 0 ,ENOMEM 12 ,ENOMSG 0 ,ENONET 0 ,ENOPKG 0 ,ENOPROTOOPT 10042 ,ENOSPC 28 ,ENOSR 0 ,ENOSTR 0 ,ENOSYS 40 ,ENOTBLK 0 ,ENOTCONN 10057 ,ENOTDIR 20 ,ENOTEMPTY 41 ,ENOTNAM 0 ,ENOTRECOVERABLE 0 ,ENOTSOCK 10038 ,ENOTSUP 0 ,ENOTTY 25 ,ENOTUNIQ 0 ,ENXIO 6 ,EOPNOTSUPP 10045 ,EOVERFLOW 0 ,EOWNERDEAD 0 ,EPERM 1 ,EPFNOSUPPORT 10046 ,EPIPE 32 ,EPROCLIM 10067 ,EPROCUNAVAIL 0 ,EPROGMISMATCH 0 ,EPROGUNAVAIL 0 ,EPROTO 0 ,EPROTONOSUPPORT 10043 ,EPROTOTYPE 10041 ,ERANGE 34 ,EREMCHG 0 ,EREMOTE 10071 ,EREMOTEIO 0 ,ERESTART 0 ,ERFKILL 0 ,EROFS 30 ,ERPCMISMATCH 0 ,ESHUTDOWN 10058 ,ESOCKTNOSUPPORT 10044 ,ESPIPE 29 ,ESRCH 3 ,ESRMNT 0 ,ESTALE 10070 ,ESTRPIPE 0 ,ETIME 0 ,ETIMEDOUT 10060 ,ETOOMANYREFS 10059 ,ETXTBSY 0 ,EUCLEAN 0 ,EUNATCH 0 ,EUSERS 10068 ,EWOULDBLOCK 10035 ,EXDEV 18 ,EXFULL 0 ,NOERROR 0 ,
5. retry, Attempt to Execute code again after an error
#!/opt/ruby/bin/ruby
def doCalc
begin
print( "Enter a number: " )
aNum = gets().chomp()
result = 100 / aNum.to_i
rescue Exception => e
result = 0
puts( "Error: " + e.to_s + "\nPlease try again." ) # Ruby 1.9如果要在字符连接中使用Exception的返回值, 需要使用to_s方法.
retry # retry on exception
else
msg = "Result = #{result}"
ensure
msg = "You entered '#{aNum}'. " + msg
end
return msg
end
doCalc
执行结果 :
./test.rb
Enter a number: 0
Error: divided by 0
Please try again.
Enter a number: "1"
Error: divided by 0
Please try again.
Enter a number: a
Error: divided by 0
Please try again.
Enter a number: 10
为了防止死循环, 可以加一个限制重试的次数.
#!/opt/ruby/bin/ruby
def doCalc
tries = 0
begin
tries += 1
print( "Enter a number: " )
aNum = gets().chomp()
result = 100 / aNum.to_i
rescue Exception => e
msg = "Error: " + e.to_s
puts( msg )
puts( "tries = #{tries}" )
result = 0
if tries < 3 then # set a fixed number of retries
retry
end
else
msg = "Result = #{result}"
ensure
msg = "You entered '#{aNum}'. " + msg
end
return msg
end
doCalc
执行结果 :
./test.rb
Enter a number: a
Error: divided by 0
tries = 1
Enter a number: b
Error: divided by 0
tries = 2
Enter a number: c
Error: divided by 0
tries = 3
6. raise, Reactivate a Handled Error
With no arguments, raises the exception in $! or raises a RuntimeError if $! is nil. With a single Stringargument, raises a RuntimeError with the string as a message. Otherwise, the first parameter should be the name of an Exception class (or an object that returns an Exception object when sent an exception message). The optional second parameter sets the message associated with the exception, and the third parameter is an array of callback information. Exceptions are caught by the rescue clause of begin...end blocks.
raise "Failed to create socket" raise ArgumentError, "No parameters", caller
begin
raise ZeroDivisionError.new( "I'm afraid you divided by Zero" )
rescue Exception => e
puts( e.class )
puts( "message: " + e.to_s )
end
执行结果 :
ZeroDivisionError
message: I'm afraid you divided by Zero
例子2 :
class NoNameError < Exception
def to_str
"No Name given!"
end
end
def sayHello( aName )
begin
if (aName == "") or (aName == nil) then
raise NoNameError
end
rescue Exception => e
puts( e.class )
puts( "error message: " + e.to_s )
puts( e.backtrace )
else
puts( "Hello #{aName}" )
end
end
sayHello(nil)
执行结果 :
NoNameError
error message: NoNameError
C:/Users/digoal/Desktop/new.rb:9:in `sayHello'
C:/Users/digoal/Desktop/new.rb:19:in `<main>'
Returns any backtrace associated with the exception. The backtrace is an array of strings, each containing either ``filename:lineNo: in `method’’’ or ``filename:lineNo.’‘
def a raise "boom" end def b a() end begin b() rescue => detail print detail.backtrace.join("\n") end
produces:
prog.rb:2:in `a' prog.rb:6:in `b' prog.rb:10
def calc
result = 1/0
rescue Exception => e
puts( e.class )
puts( e )
result = nil
return result
end
class X
@@x = 1/0
rescue Exception => e
puts( e.class )
puts( e )
end
module Y
@@x = 1/0
rescue Exception => e
puts( e.class )
puts( e )
end