next up previous contents index
Search Next: Continuations Up: Einführung in Ruby Previous: Tastatur und Standardausgabe   Contents   Index

Ausnahme- und Fehlerbehandlung

I never make exceptions. An exception disproves the rule.
Sherlock Holmes

Hugh Eng Ah, the "`Birds fly. Except penguins, kiwis, ostriches, ..."' problem


\epsfig{height=24pt,file=images/ruby.eps}Exceptions bieten ebenso wie throw und catch die Möglichkeit, den Programmablauf nicht lokal zu beeinflussen. Allerdings sollten sie aus semantischen Gründen wirklichen Ausnahmesituationen im Sinne von Fehlern vorbehalten bleiben. Sie ermöglichen eine Trennung zwischen dem "`normalen"' Algorithmus und der Behandlung von darin hervorgerufenen Fehlern.

In der folgenden Syntaxübersicht bezeichnen "zitierte" Begriffe wörtlich einzugebenden Text, [geklammerte] Ausdrücke sind optional, sind sie mit + markiert, können sie mehrfach wiederholt werden. Bei den <so> markierten Stellen fügt man eigenen Code bzw. eigene Klassen ein.

"begin" 
  <heikler Code> 
[rescue [<AusnahmeKlasse> ["," <AusnahmeKlasse>]+]
  ["=>" <Variable>]
  <Fehlerbehandlungs-Code>
]+ 
["else" 
  <Dieser Code wird nur ausgeführt,
  wenn keine Ausnahme aufgetreten ist>
]
["ensure" 
  <Dieser Code wird in jedem Fall ausgeführt>
]
"end"

Ein Beispiel:

begin
  print 1
  raise "Test-Exception"
  print 2
rescue
  print 3
else
  print 5
ensure
  print 4
end #-> 134

Der optionale ensure-Teil dient dazu, unbedingt notwendige Aufräumarbeiten auszuführen und wird auf jeden Fall ausgeführt. Der ebenfalls optionale else-Zweig wird nur verwendet, wenn zwischen begin und rescue keine Ausnahme ausgelöst worden ist. rescue ohne Exception-Angabe dient als "`Default-Handler"', der alle Exceptions bearbeitet, die vorher nicht aufgefangen wurden.

In den Behandlungsblöcken kann man mit retry die Ausführung des heiklen Codeabschnitts wiederholen.

i = 1
begin
  print "Login (#{i}): "
  user = gets.chomp
  raise "Einbruch!" if user != "ruby"
rescue RuntimeError
  puts "#{user} kenn' ich nicht."
  i += 1
  retry
else
  puts "Willkommen!"
end

# ergibt

Login (1): java
java kenn' ich nicht.
Login (2): ruby
Willkommen!


\epsfig{height=36pt,file=images/chan.eps}rescue fängt alle StandardError- und davon abgeleitete Ausnahmen (wie zum Beispiel RuntimeError) ab, wenn kein expliziter Ausnahmetyp angegeben wird.

Es gibt jedoch auch Ausnahme(-Klasse)n, welche nicht von RuntimeError abgeleitet sind: ScriptError, NoMemoryError etc. \epsfig{height=10pt,file=images/ruby.eps}

raise kann auch mit einer bestimmten Ausnahme-Klasse aufgerufen werden, um unterschiedliche Typen von Ausnahmen zu erzeugen, die getrennt behandelt werden können. Alle Ausnahme-Klassen - also auch eigens definierte - müssen vonException oder einer ihrer Unterklassen abgeleitet sein. Ein raise ohne Zusatz erzeugt eine RuntimeError-Ausnahme. Ruby durchsucht die rescue-Zweige, bis ein Zweig mit der Klasse der Ausnahme oder einer ihrer Oberklassen gefunden wird.

begin
  print 1
  raise ArgumentError, "Test-Exception"
  print 2
rescue ArgumentError
  print 5
rescue
  print 3
ensure
  print 4
end #-> 154

Mit begin/rescue können auch besondere Tastaturereignisse abgefangen werden, zum Beispiel der Tastendruck Strg+C, mit dem man unter Unix ein Programm abbricht:

begin
  loop do
  end
rescue Interrupt
  puts "Abbruch"
end


\epsfig{height=36pt,file=images/chan.eps}Im folgenden Beispiel erzielen wir den gleichen Effekt, fangen aber mit der trap-Methode das Signal auf, bevor es Ruby in seiner DEFAULT-Interrupt-Routine in eine Interrupt-Ausnahme wandelt und uns diese per raise zukommen lässt.

begin
  trap("INT"){ raise }
  while true
  end
rescue
  puts "Abbruch"
  trap("INT", "DEFAULT")
end
Das trap im rescue-Zweig stellt das Standardverhalten wieder her. \epsfig{height=10pt,file=images/ruby.eps}


next up previous contents index
Search Next: Continuations Up: Einführung in Ruby Previous: Tastatur und Standardausgabe   Contents   Index
(C) 2002 by dpunkt.de, Armin Roehrl, Stefan Schmiedl, Clemens Wyss 2002-01-20