Anfang des Inhaltsbereichs

Ausnahmen behandeln Dokument im Navigationsbaum lokalisieren

Das Auftreten einer Ausnahme dient in der Regel der Anzeige einer Fehlersituation. Der Behandler einer Ausnahme muß versuchen, den aufgetretenen Fehler zu beheben, eine Alternativlösung zu suchen oder, falls dies nicht möglich ist, zumindest den betroffenen Kontext in einen konsistenten Zustand zu bringen und dann den Fehler weiterzugeben. Ist entlang einer Aufrufhierarchie kein Behandler für eine Ausnahme vorhanden, wird das Programm mit einem Laufzeitfehler beendet. Da Ausnahmen nicht über Programmaufrufe hinweg behandelt werden können, müssen zur Verhütung eines Laufzeitfehlers alle eventuellen Ausnahmen innerhalb des Programms selbst behandelt werden. Ausgenommen von dieser Regel ist nur das Coding innerhalb von Prozeduren, deren Ausnahmen sehr wohl an (externe) Aufrufer propagiert werden kann.

Die Behandlung klassenbasierter Ausnahmen erfolgt in folgender Kontrollstruktur:

TRY.

  ...                       " TRY block (application coding)

  CATCH cx_... cx_... ...

    ...                     " CATCH block (exception handler)

  CATCH cx_... cx_... ...

    ...                     " CATCH block (exception handler)

  ...

  CLEANUP.

    ...                     " CLEANUP block (cleanup context)

ENDTRY.

Die Anweisung TRY öffnet eine mit ENDTRY abzuschließende Kontrollstruktur, in der drei Anweisungsblöcke in vorgegebener Reihenfolge aufgeführt werden können (aber nicht müssen):

  1. Ein TRY-Block, in dem Ausnahmen auftreten können.
    Dieser Anweisungsblock besteht aus allen Anweisungen, die zwischen TRY und der Anweisung CATCH stehen.
  2. Ein oder mehrere CATCH-Blöcke zum Abfangen von Ausnahmen.
    Diese Anweisungsblöcke werden mit CATCH eingeleitet und durch ein weiteres CATCH, CLEANUP oder ENDTRY beendet.
  3. Ein CLEANUP-Block für Aufräumarbeiten nach dem Abfangen.
    Dieser Anweisungsblock wird durch CLEANUP eingeleitet und durch ENDTRY beendet. Eine TRY-ENDTRY-Struktur darf maximal einen CLEANUP-Block an genau dieser Position enthalten.

TRY-ENDTRY-Strukturen sind wie alle ABAP-Kontrollstrukturen in beliebige Anweisungsblöcke schachtelbar (siehe Programmablaufsteuerung). Insbesondere können also auch obige drei Anweisungsblöcke wieder komplette TRY-ENDTRY-Blöcke enthalten. Wie alle ABAP-Kontrollstrukturen muß jede TRY-ENDTRY-Struktur vollständig in einem Verarbeitungsblock (Ereignisblock, Dialogmodul, Prozedur) enthalten sein. Das Anwendungscoding einer TRY-ENDTRY-Struktur kann also nicht mehrere Verarbeitungsblöcke umfassen.

TRY-Block

Im TRY-Block steht das Anwendungscoding dessen Ausnahmen behandelt werden sollen. Dieser Anweisungsblock wird sequentiell bearbeitet. Er kann weitere Kontrollstrukturen und Aufrufe von Prozeduren oder von anderen ABAP-Programmen beinhalten.

Wenn im TRY-Block oder einer dort aufgerufenen Prozedur eine Ausnahme auftritt, sucht das System zuerst nach einer CATCH-Anweisung der gleichen TRY-ENDTRY-Struktur und dann vonn innen nach außen nach einer CATCH-Anweisung in eventuell umschließenden TRY-ENDTRY-Strukturen, die das Ereignis behandelt und verzweigt gegebenenfalls zu diesem Behandler. Falls kein Behandler gefunden wird, die TRY-ENDTRY-Struktur aber innerhalb einer Prozedur steht und, versucht das System die Ausnahme an den Aufrufer zu propagieren (siehe auch Ausnahmen propagieren). In allen Verarbeitungsblöcken ohne lokalen Datenbereich (Ereignisblöcke, Dialogmodule) können Ausnahmen nicht propagiert werden und es kommt bei einem fehlenden Behandler direkt zu einem Laufzeitfehler.

Wenn in einem TRY-Block keine Ausnahme auftritt, wird die Programmausführung nach seiner Beendigung direkt hinter ENDTRY fortgesetzt.

CATCH-Block

Ein Catch-Block enthält den Ausnahmebehandler, der ausgeführt wird, wenn eine bestimmte Ausnahme im TRY-Block der gleichen TRY-ENDTRY-Struktur aufgetreten ist. Eine TRY-ENDTRY-Struktur kann mehrere Ausnahmebehandler enthalten. Die Syntax zur Einleitung eines Ausnahmebehandlers ist:

CATCH cx_... cx_... INTO ref.

Hinter CATCH können beliebig viele Ausnahmeklassen angegeben werden. Dadurch wird ein Ausnahmebehandler für alle angegebenen Ausnahmeklassen und deren Unterklassen definiert.

Das System durchsucht nach dem Auftreten einer Ausnahme die aufgeführten Ausnahmebehandler in der angegebenen Reihenfolge. Der erste Ausnahmebehandler, dessen CATCH-Anweisung die entsprechende Ausnahmeklasse oder eine ihrer Oberklassen enthält, wird ausgeführt. Danach wird direkt hinter ENDTRY verzweigt. Eventuell folgende Ausnahmebehandler werden nicht berücksichtigt. Aus diesem Grund muß sich die Reihenfolge verschiedener Ausnahmebehandler innerhalb einer TRY-ENDTRY-Struktur nach der Vererbungshierarchie der angegebenen Ausnahmeklassen richten.

Die Syntax-Prüfung stellt sicher, daß die Behandler für speziellere Ausnahmen (Unterklassen) nur vor den Behandlern für allgemeinere Ausnahmen (Oberklassen) aufgeführt werden können. Beispielsweise kann ein Behandler für die allgemeinste Ausnahmeklasse CX_ROOT immer nur der letzte Anweisungsblock vor CLEANUP bzw. ENDTRY sein, ansonsten würden alle folgenden Behandler nie erreicht.

Mit dem Zusatz INTO kann eine Referenz auf das Ausnahmeobjekt in eine Referenzvariable gestellt werden. Dadurch ist es im Behandler möglich, auf die Attribute des Ausnahmeobjekts zuzugreifen. Die Referenzvariable muß zur Ausnahme passen. Ihr statischer Typ muß also die Ausnahmeklasse selbst oder eine ihrer Oberklassen sein. Es empfiehlt sich, nicht die ganz allgemeine Klasse OBJECT zu verwenden, sondern eine Ausnahmeklasse unterhalb oder gleich CX_ROOT. Nur diese Klassen enthalten die für Ausnahmen relevanten Methoden.

CLEANUP-Block

Wenn in einer TRY-ENDTRY-Struktur kein Behandler für eine Ausnahme gefunden wird, wird wie oben erwähnt von innen nach außen in den umschließenden TRY-ENDTRY-Strukturen nach einem Behandler gesucht. Wird auch dort kein Behandler gefunden, wird versucht die Ausnahme an einen Prozeduraufrufer zu propagieren.

In jeder TRY-ENDTRY-Struktur kann genau ein CLEANUP-Block definiert werden. Dieser wird ausgeführt bevor die TRY-ENDTRY-Struktur verlassen wird, wenn für eine Ausnahme kein Behandler gefunden wurde, die Ausnahme aber in einer umschließenden TRY-ENDTRY-Struktur behandelt oder an einen Aufrufer propagiert wird.

Im CLEANUP-Block können Aufräumarbeiten für den Kontext des TRY-Block ausgeführt werden. Beispielsweise müssen oft Objekte in einen konsistenten Zustand gebracht oder externe Ressourcen freigegeben werden, auf die ein äußerer Behandler keinen Zugriff mehr hat. Durch die Schachtelung von TRY-ENDTRY-Blöcken und die mögliche Propagierung von Ausnahmen, kann es vorkommen, daß erst mehrere CLEANUP-Blöcke ausgeführt werden, bevor eine Ausnahme tatsächlich behandelt wird.

Da der CLEANUP-Block lediglich dazu dient, die Konsistenz eines Kontexts wieder herzustellen, darf er nur auf normalem Wege, d.h.durch Erreichen seiner letzten Anweisung, verlassen werden. Aus diesem Grund sind alle den Kontrollfluß ändernden Anweisungen, die zum Verlassen des CLEANUP-Block führen und einen Verarbeitungblock des gleichen Programms ansteuern würden, untersagt. Dies gilt zum Beispiel für Anweisungen wie RETURN, STOP etc. Aus dem gleichen Grund muß jede Ausnahme, die innerhalb eines CLEANUP-Blocks auftritt, auch dort behandelt werden. Erlaubt ist dagegen das Verlassen des gesamten Programms (LEAVE PROGRAM) oder ein Aufrruf von Prozeduren, Programmen und auch Dynprofolgen, wenn in den CLEANUP-Block zurückgekehrt wird. Die Laufzeitumgebung stellt auf alle Fälle fest, wenn ein CLEANUP-Block illegal verlassen wird und reagiert dann mit einem Laufzeitfehler.

Beispiel

Beispiel

report DEMO_HANDLE_EXCEPTIONS.

parameters NUMBER type I.

data RESULT type P decimals 2.
data OREF type ref to CX_ROOT.
data TEXT type STRING.

start-of-selection.

  write: / 'Testing divison and Sqare root with', NUMBER.
  uline.

  try.
    if ABS( NUMBER ) > 100.
      raise exception type CX_DEMO_ABS_TOO_LARGE.
    endif.
    try.
      RESULT =  1 / NUMBER.
      write: / 'Result of division:', RESULT.
      RESULT = SQRT( NUMBER ).
      write: / 'Result of square root:', RESULT.
      catch CX_SY_ZERODIVIDE into OREF.
        TEXT = OREF->GET_TEXT( ).
      cleanup.
        clear RESULT.
    endtry.
    catch CX_SY_ARITHMETIC_ERROR into OREF.
      TEXT = OREF->GET_TEXT( ).
    catch CX_ROOT into OREF.
      TEXT = OREF->GET_TEXT( ).
  endtry.
  if not TEXT is initial.
    write / TEXT.
  endif.
  write: / 'Final result:', RESULT.

In diesem Beispiel ist eine TRY-ENDTRY-Struktur in den TRY-Block einer anderen TRY-ENDTRY-Struktur geschachtelt. Folgende vier Szenarien werden in dem Beispiel demonstriert:

Abfangen einer Ausnahme durch Behandlung einer Oberklasse

Falls NUMBER größer 100 ist, wird im TRY-Block der äußeren TRY-ENDTRY-Struktur die im Exception Builder der ABAP Workbench selbstdefinierte Ausnahme CX_DEMO_ABS_TOO_LARGE ausgelöst. Diese Ausnahme ist Unterklasse der allgemeinsten Ausnahme CX_ROOT und wird vom zweiten CATCH-Block der gleichen TRY-ENDTRY-Struktur behandelt.

Abfangen einer Ausnahme durch Behandlung der passenden Klasse

Falls NUMBER gleich Null ist, wird im TRY-Block der inneren TRY-ENDTRY-Struktur durch die Division die im System vordefinierte Ausnahme CX_SY_ZERODIVIDE ausgelöst und im entsprechenden CATCH-Block der gleichen TRY-ENDTRY-Struktur behandelt.

Ausführung eines CLEANUP-Blocks vor dem Abfangen einer Ausnahme

Fall NUMBER eine negative Zahl ist, wird im TRY-Block der inneren TRY-ENDTRY-Struktur durch die Funktion SQRT die im System vordefinierte Ausnahme CX_SY_ARG_OUT_OF_DOMAIN ausgelöst. Da in der inneren TRY-ENDTRY-Struktur kein Behandler für diese Ausnahme definiert ist, wohl aber in der äußeren TRY-ENDTRY-Struktur, wird der CLEANUP-Block der inneren TRY-ENDTRY-Struktur ausgeführt. Dann wird die Ausnahme im ersten CATCH-Block der äußeren TRY-ENDTRY-Struktur behandelt, da CX_SY_ARG_OUT_OF_DOMAIN Unterklasse von CX_SY_ARITHMETIC_ERROR ist.

Keine Ausnahme

In allen anderen Fällen wird keine Ausnahme ausgelöst und dir TRY-Blöcke beider TRY-ENDTRY-Strukturen werden vollständig abgearbeitet.

In allen CATCH-Anweisungen des Beispiels werden die Objektreferenzen auf die entsprechenden Ausnahmeobjekte in der Referenzvariablen OREF gespeichert. Mit Hilfe von OREF greifen die einzelnen Behandler auf die Ausnahmetexte der einzelnen Ausnahmeobjekte zu und speichern sie in der Stringvariablen TEXT.

Ende des Inhaltsbereichs