C-Sharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript | SQL | PHP | Angular | HTML
Note: A Ruby program would normally terminate when the ZeroDivisionError is encountered.
However: If you enclose the division statement in a begin block, we have an opportunity to catch or "rescue" the error.
Rescue: In this program we rescue an invalid division expression. We set the result to zero.
Ruby program that uses begin, rescue
# Enter a protected region.
begin
# Try to divide by zero.
i = 1 / 0
rescue ZeroDivisionError
# Handle the error.
puts "ERROR"
i = 0
end
# Display final value.
puts i
Output
ERROR
0
Note: Usually a message that states no errors occurred is not needed, but it works well for demonstration.
Tip: In real programs, exceptions usually should not be the "normal" case. Normal operation should have no exceptional events.
Ruby program that uses else
divisor = 2
begin
reciprocal = 1 / divisor
rescue
reciprocal = 0
else
# This is reached when no error is encountered in "begin."
puts "NO ERROR"
end
puts reciprocal
Output
NO ERROR
0
Type: Raise can create an exception of any type. We can specify the type as the first argument to "raise."
Ruby program that uses raise
begin
# This is a bad program.
raise "Bad program error"
rescue RuntimeError => e
# This prints the error message.
puts e
end
Output
Bad program error
And: With a raise statement, with no argument, the present exception is raised again.
However: We trigger an IndexError. And then, in the "rescue" block, we reraise it. We then rescue it at the method's calling location.
Ruby program that reraises an error
def problem(n)
begin
raise IndexError, n if n < 0
rescue
# Reraise this error.
raise
end
end
# Call the problem method.
begin
problem(-1)
rescue IndexError
# Handle the re-raised error.
puts "IndexError encountered!"
end
Output
IndexError encountered!
Throw: If a throw occurs within the statements in a catch block, the catch block is exited.
Tip: With throw and catch, the labels are matched. In many ways these statements act like "goto" but can pass method boundaries.
Also: For nested loops and method calls, catch and throw can be useful. With them we can reduce the need for flag variables to direct flow.
Ruby program that uses catch, throw
def method(a)
puts a
# Throw on a negative number.
if a < 0
throw :negative
end
end
# These statements continue until :negative is thrown.
catch :negative do
method(0)
method(-1)
puts "NOT REACHED"
end
puts "END"
Output
0
-1
END
Note: We usually change variables or an external file before retrying. We attempt to correct the program's state.
Ruby program that uses retry
denominator = 0
begin
# Divide with the denominator integer.
result = 1 / denominator
puts(result)
rescue
# Change denominator to 1 and try again.
puts("Rescuing")
denominator = 1
retry
end
Output
Rescuing
1
Tip: An ensure block can be used to perform some cleanup (like deleting a temporary file). It can display a completion message.
Ruby program that uses ensure
y = 10
begin
x = 100 / y
puts "In begin..."
rescue
# This is not reached.
puts "In rescue..."
ensure
# Do some cleanup.
puts "In ensure..."
end
Output
In begin...
In ensure...
Version 1: This code runs a loop 50,000 times. Every 5 iterations, an exception is raised. We handle it with rescue.
Version 2: This code checks the iterator variable "x" against zero each time. It handles zero with a special case.
IteratorResult: It is faster, for a frequent error, to test values with an if-statement. Raising the exception is slower.
Ruby program that times begin, if
n1 = Time.now.usec
# Version 1: use begin, rescue.
50000.times do
5.times do |x|
begin
i = 1 / x
rescue
i = 0
end
end
end
n2 = Time.now.usec
# Version 2: use if, else.
50000.times do
5.times do |x|
if x == 0
i = 0
else
i = 1 / x
end
end
end
n3 = Time.now.usec
# Compute milliseconds total.
puts ((n2 - n1) / 1000)
puts ((n3 - n2) / 1000)
Output
171 ms begin/rescue
15 ms if/else
Tip: If a non-essential part of code fails, you may be able to continue the rest of the program without much concern.
Tip 2: Logging an error code in your application is a good way to later correct or debug the application.