Code analysieren und testen
Korrekte Verwendung von Datentypen und Typkonvertierungen
Verarbeitung von Zeichenfeldern
Code-Pushdown in ABAP SQL verwenden
Performance interner Tabellen verbessern
Implementieren von Berechtigungsprüfungen
Effektiven objektorientierten Code entwerfen
Ausnahmeklassen definieren und mit Ausnahmeklassen arbeiten
Dokumentation zum ABAP-Quelltext hinzufügen

Arbeiten mit Ausnahmeklassen

Objective

After completing this lesson, you will be able to arbeiten Sie mit Ausnahmeklassen.

Ausnahmebehandlung

Zuvor haben wir uns in diesem Kurs mit der Fehlerbehandlung mit den TRY-, CATCH- und ENDTRY-Anweisungen befasst. Nach der TRY-Anweisung kommt die Anweisung, die zu einem Fehler führen kann. Wenn der Fehler auftritt, springt das System zur CATCH-Anweisung und verarbeitet deren Inhalt. Unabhängig davon, was passiert, führt die Methode die Verarbeitung nach der ENDTRY-Anweisung durch.

In einem TRY…ENDTRY -Block können Sie mehrere CATCH-Anweisungen einbinden. Auf diese Weise können Sie verschiedene Ausnahmen unterschiedlich behandeln.

Sie können mehrere Ausnahmen in einer einzelnen CATCH-Anweisung auflisten. In diesem Beispiel wird derselbe CATCH-Block verarbeitet, wenn das System entweder cx_sy_arithmetic_error oder cx_sy_zerodivide auslöst.

Wenn Sie eine Klasse in einer CATCH-Anweisung auflisten, verarbeitet das System den entsprechenden Block, wenn eine Ausnahme mit dieser Klasse oder einer ihrer Unterklassen ausgelöst wird. In diesem Beispiel ist cx_sy_arithmetic_error eine Oberklasse von cx_sy_arithmetic_overflow und cx_sy_zerodivide. Gleichzeitig wird der Block verarbeitet, wenn eine Ausnahme vom Typ einer der Unterklassen ausgelöst wird.

Alle Ausnahmeklassen sind Teil einer Vererbungshierarchie, deren oberste Oberklasse die Klasse cx_root ist. Wie wir bereits gesehen haben, springt das System, wenn Sie eine Oberklasse in einer CATCH-Anweisung verwenden, dorthin, wenn eine Ausnahme mit dem Typ einer ihrer Unterklassen ausgelöst wird. Da alle Ausnahmeklassen Unterklassen von cx_root sind, reicht die Anweisung CATCH cx_root aus, um eine Ausnahme abzufangen.

Reihenfolge der CATCH-Anweisungen

Wenn Sie CATCH-Anweisungen schreiben, müssen Sie die spezifischste Klasse (oder die spezifischsten Klassen) an erster Stelle und die allgemeinste an letzter Stelle setzen. Wenn Sie eine Oberklasse über einer ihrer Unterklassen platzieren, verursachen Sie einen Syntaxfehler. Dies liegt daran, dass das System den spezifischen CATCH-Block nicht verarbeiten konnte, da er von dem generischeren Block überschattet wird.

Der INTO -Zusatz

Jede Ausnahme wird durch ein Objekt repräsentiert. Sie können dieses Objekt in eine Referenzvariable stellen und damit arbeiten, z.B. um den Fehlertext aus der Ausnahmeklasse mit der Methode get_text( ) abzurufen, wie im Beispiel hier gezeigt.

Sie können eine Inline-Deklaration in der CATCH -Anweisung verwenden, um sicherzustellen, dass die Referenzvariable mit dem richtigen Typ deklariert wird.

Am häufigsten wird mit dem Ausnahmeobjekt gearbeitet, indem seine Methode get_text( ) aufgerufen wird. Ausnahmeobjekte können jedoch über andere Attribute und Methoden verfügen, um Sie bei der Fehlerbehebung zu unterstützen.

Ausnahmeklassen können Attribute haben, die genauer beschreiben, was schiefgelaufen ist. Diese Attribute werden häufig verwendet, um die Platzhalter von Nachrichten zu füllen. Sie definieren ein Attribut im öffentlichen Bereich der Ausnahmeklasse mit seinem entsprechenden Namen und Typ.

Um ein Attribut beim Auslösen der Ausnahme zu füllen, benötigen Sie einen entsprechenden Importparameter des Konstruktors der Ausnahmeklasse. Sie können diesen Importparameter mit einem Quickfix generieren. Positionieren Sie den Cursor auf dem Methodennamen constructor, und drücken Sie Strg + 1. Wählen Sie das Quickfix Konstruktor neu generieren.

Ausnahmen propagieren

Eine Methode kann eine Ausnahme entlang der Aufrufkette propagieren. Statt die Ausnahme mit der CATCH-Anweisung zu behandeln, nimmt die Methode die RAISING-Klausel in ihre Definition auf. Dies zeigt den Aufrufern der Methode an, dass ihnen die Ausnahme übergeben werden kann.

Wenn die Ausnahme entlang der Aufrufkette nirgends abgefangen wird, tritt ein Laufzeitfehler auf.

Das Attribut previous

Manchmal fängt eine Methode innerhalb einer Aufrufkette eine Ausnahme ab und löst als Antwort eine andere Ausnahme aus, damit der eigene Aufrufer sie abfangen kann. Dies kann z.B. der Fall sein, wenn ein Framework eine Ausnahme auslöst, die zu technisch orientiert ist, damit die Anwendung verarbeitet werden kann. Die Methode, die eine eigene Ausnahme auslöst, übergibt möglicherweise die erste Ausnahme. Dies kann über das Attribut previous der Ausnahmeklasse erfolgen.

Wenn Sie eine Ausnahme auslösen, können Sie eine Instanz einer Ausnahmeklasse an den Importparameter previous übergeben. Dadurch wird das Ausnahmeobjekt an die neue Ausnahme angehängt. Eine Methode, die die zweite Ausnahme abfängt, kann über das öffentliche schreibgeschützte Attribut previous auf das erste Ausnahmeobjekt zugreifen.

Da previous in der Oberklasse cx_root implementiert ist, steht sie in allen Ausnahmeklassen zur Verfügung.

Probieren Sie es aus: Ausnahmeklassen

  1. Legen Sie eine neue Klasse an, die das Interface IF_OO_ADT_CLASSRUN implementiert.
  2. Kopieren Sie den folgenden Code-Snippet in den Implementierungsteil der Methode if_oo_adt_classrun~main( ).
    Code Snippet
    12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
    DATA number1 TYPE i VALUE 2000000000. DATA number2 TYPE p LENGTH 2 DECIMALS 1 VALUE '0.5'. DATA result TYPE i. TRY. result = number1 / number2. CATCH cx_sy_arithmetic_overflow. out->write( 'Arithmetic Overflow' ). CATCH cx_sy_zerodivide. out->write( 'Division by zero' ). ENDTRY. number2 = 0. TRY. result = number1 / number2. CATCH cx_sy_arithmetic_overflow. out->write( 'Arithmetic Overflow' ). CATCH cx_sy_zerodivide. out->write( 'Division by zero' ). ENDTRY. TRY. result = number1 / number2. CATCH cx_sy_arithmetic_overflow cx_sy_zerodivide. out->write( 'Arithmetic overflow or division by zero' ). ENDTRY. TRY. result = number1 / number2. CATCH cx_sy_arithmetic_error. out->write( 'Caught both exceptions using their common superclass' ). ENDTRY. TRY. result = number1 / number2. CATCH cx_root. out->write( 'Caught any exception using CX_ROOT' ). ENDTRY. TRY. result = number1 / number2. CATCH cx_root into data(Exception). out->write( 'Used INTO to intercept the exception object' ). out->write( 'The get_Text( ) method returns the following error text: ' ). out->write( Exception->get_text( ) ). ENDTRY.
  3. Aktivieren Sie die Klasse mit Strg + F3.
  4. Spielen Sie mit dem Coding, um sich damit vertraut zu machen.

Mit Ausnahmeobjekten arbeiten

Sie verbessern Ihren Code, indem Sie auf Ausnahmeobjekte, d.h. Instanzen von Ausnahmeklassen, zugreifen. Sie verwenden Konstruktorparameter, um Attributwerte von Ausnahmeobjekten zu setzen.

Vorlage:

  • /LRN/CL_S4D401_OOS_FACTORY (globale Klasse)

Lösung:

  • /LRN/CL_S4D401_EXS_HANDLING (globale Klasse)

Aufgabe 1: Vorlage kopieren (optional)

Kopieren Sie die Vorlagenklasse /LRN/CL_S4D401_OOS_FACTORY. Wenn Sie die vorherige Übung abgeschlossen haben, können Sie diese Aufgabe überspringen und mit der Bearbeitung Ihrer Klasse ZCL_##_SOLUTION fortfahren.

Schritte

  1. Kopieren Sie die Klasse /LRN/CL_S4D401_OOS_FACTORY in eine Klasse in Ihrem eigenen Paket (Namensvorschlag: ZCL_##_SOLUTION, wobei ## für Ihre Gruppennummer steht).

    1. Klicken Sie im Project Explorer mit der rechten Maustaste auf die Klasse /LRN/CL_S4D401_OOS_FACTORY, um das Kontextmenü zu öffnen.

    2. Wählen Sie im Kontextmenü Duplizieren....

    3. Geben Sie den Namen Ihres Pakets in das Feld Package ein. Geben Sie im Feld NameZCL_##_SOLUTION ein, wobei ## für Ihre Gruppennummer steht.

    4. Wählen Sie Next.

    5. Bestätigen Sie den Transportauftrag, und wählen Sie Finish.

  2. Aktivieren Sie die Kopie.

    1. Drücken Sie Strg + F3, um die Klasse zu aktivieren.

Aufgabe 2: Ausnahmenobjekte aufrufen

Passen Sie in Ihrer globalen Klasse die Implementierung der Methode IF_OO_ADT_CLASSRUN~MAIN an. Erweitern Sie die Ausnahmebehandlung beim Aufruf der Factory-Methode GET_INSTANCE. In beiden CATCH -Blöcken erhalten Sie eine Referenz auf das Ausnahmeobjekt und extrahieren den Ausnahmetext. Ersetzen Sie den literalen Text für die Konsolenausgabe durch die Ausnahmetexte.

Schritte

  1. Navigieren Sie zur Implementierung der Methode IF_OO_ADT_CLASSRUN~MAIN Ihrer globalen Klasse.

    1. Öffnen Sie die globale Klasse, und wechseln Sie zur Registerkarte Globale Klasse.

  2. Lassen Sie in der ersten CATCH -Anweisung eine Referenzvariable auf das Ausnahmeobjekt zeigen, d.h. die Instanz der Ausnahmeklasse CX_ABAP_INVALID_VALUE (Namensvorschlag für die Variable: exc_inv).

    Hinweis

    Sie können eine Inline-Deklaration verwenden, um die Referenzvariable mit dem richtigen Typ zu deklarieren.
    1. Passen Sie den Quelltext wie folgt an:

      ABAP
      1
      CATCH cx_abap_invalid_value INTO DATA(exc_inv).
    2. Um den Typ der Variablen exc_inv anzuzeigen, positionieren Sie den Cursor auf exc_inv, und drücken Sie F2.

  3. Kommentieren Sie im Block CX_ABAP_INVALID_VALUE CATCH den Aufruf der Methode out->write aus. Rufen Sie den Ausnahmetext aus dem Ausnahmeobjekt ab, und verwenden Sie ihn in einem neuen Aufruf der Methode out->write.

    1. Passen Sie den Quelltext wie folgt an:

      ABAP
      123
      CATCH cx_abap_invalid_value INTO DATA(exc_inv). * out->write( |Carrier { c_carrier_id } does not exist| ). out->write( exc_inv->get_text( ) ).
  4. Gleiches gilt für die zweite CATCH-Anweisung und den CATCH-Block (Namensvorschlag für die Referenzvariable: exc_auth).

    1. Passen Sie den Quelltext wie folgt an:

      ABAP
      123
      CATCH cx_abap_auth_check_exception INTO DATA(exc_auth). * out->write( |No authorization to display carrier { c_carrier_id }| ). out->write( exc_auth->get_text( ) ).
  5. Aktivieren und testen Sie Ihren Code. Passen Sie den Wert der Konstante c_carrier_id an, um die verschiedenen Ausnahmen zu provozieren.

    1. Drücken Sie Strg + F3, um den Quelltext zu aktivieren.

    2. Drücken Sie F9, um den Code als Konsolen-App auszuführen.

    3. Setzen Sie den Wert der Konstante c_carrier_id auf XX, um die Ausnahme für einen ungültigen Wert zu provozieren.

    4. Setzen Sie den Wert der Konstante c_carrier_id auf UA, um die Ausnahme für die fehlende Berechtigung zu provozieren.

Aufgabe 3: Gruppen von Ausnahmen behandeln

Passen Sie in der lokalen Testklasse LTCL_FIND_FLIGHTS die Implementierung der Methode CLASS_SETUP an. Behandeln Sie beim Aufruf der Factory-Methode GET_INSTANCE alle möglichen Ausnahmen in nur einem CATCH-Block. Geben Sie im Falle einer Ausnahme die Fail-Methode mit dem Ausnahmetext aus dem Ausnahmeobjekt anstelle der generischen Fehlermeldung „lcl_carrier kann nicht instanziiert" werden an.

Schritte

  1. Navigieren Sie zur Implementierung der Methode CLASS_SETUP der lokalen Testklasse LTCL_FIND_FLIGHTS.

    1. Wechseln Sie auf die Registerkarte Testklassen.

    2. Blättern Sie zur Anweisung METHOD class_setup.

  2. Passen Sie nach dem Aufruf der Methode GET_INSTANCE die Ausnahmebehandlung an. Kommentieren Sie den Catch-Block für die Ausnahmeklasse CX_ABAP_INVALID_VALUE und ersetzen Sie die Ausnahmeklasse CX_ABAP_AUTH_CHECK_EXCEPTION durch CX_ROOT.

    1. Passen Sie den Quelltext wie folgt an:

      ABAP
      1234567
      TRY. the_carrier = lcl_carrier=>get_instance( i_carrier_id = some_flight_data-carrier_id ). * CATCH cx_abap_invalid_value. * cl_abap_unit_assert=>fail( `Unable to instantiate lcl_carrier` ). CATCH cx_root. cl_abap_unit_assert=>fail( `Unable to instantiate lcl_carrier` ). ENDTRY.
  3. Fügen Sie der CATCH-Anweisung eine INTO-Klausel mit einer inline deklarierten Referenzvariablen hinzu (Namensvorschlag für die Variable: exc_root).

    1. Passen Sie den Quelltext wie folgt an:

      ABAP
      1
      CATCH cx_root INTO DATA(exc_root).
    2. Um den Typ der Variablen exc_root anzuzeigen, positionieren Sie den Cursor auf exc_root, und drücken Sie F2.

  4. Verwenden Sie im Block CX_ROOT CATCH den Ausnahmetext als Eingabe für die Methode CL_ABAP_UNIT_ASSERT=>fail.

    1. Passen Sie den Quelltext wie folgt an:

      ABAP
      12
      CATCH cx_root INTO DATA(exc_root). cl_abap_unit_assert=>fail( exc_root->get_text( ) ).
  5. Aktivieren Sie den Code.

    1. Drücken Sie Strg + F3.

Aufgabe 4: Attribute von Ausnahmeobjekten setzen

Passen Sie das Auslösen der Ausnahmen in der Factory-Methode GET_INSTANCE an. Verwenden Sie beim Auslösen der Ausnahme CX_ABAP_INVALID_VALUE einen entsprechenden Konstruktorparameter, um die ungültige Träger-ID in den Ausnahmetext aufzunehmen. Verwenden Sie beim Auslösen der Ausnahme CX_ABAP_AUTH_CHECK_EXCEPTION einen geeigneten Konstruktorparameter, um einen geeigneteren Ausnahmetext auszuwählen.

Schritte

  1. Navigieren Sie zur Implementierung der Methode GET_INSTANCE der lokalen Klasse LCL_CARRIER.

    1. Setzen Sie z.B. in der Methode IF_OO_ADT_CLASSRUN~MAIN den Cursor auf get_instance und drücken Sie F3.

  2. Analysieren Sie die Signatur der Methode CONSTRUCTOR der Ausnahmeklasse CX_ABAP_INVALID_VALUE.

    1. Positionieren Sie in der Anweisung RAISE EXCEPTION den Cursor auf CX_ABAP_INVALID_VALUE, und drücken Sie F2, um die ABAP-Elementinformationen für die Ausnahmeklasse anzuzeigen.

    2. Wählen Sie im Dialogfenster den Konstruktor, um die Elementinformationen für die Methode CONSTRUCTOR anzuzeigen.

  3. Passen Sie die Anweisung RAISE EXCEPTION für die Ausnahmeklasse CX_ABAP_INVALID_VALUE an. Geben Sie den Konstruktorparameterwert mit der ungültigen Warenträger-ID an.

    Notiz

    Sie müssen eine Typkonvertierung durchführen, da value und i_carrier_id keinen identischen Typ haben.
    1. Passen Sie den Quelltext wie folgt an:

      ABAP
      123
      RAISE EXCEPTION TYPE cx_abap_invalid_value EXPORTING value = CONV #( i_carrier_id ).
  4. Passen Sie die Anweisung RAISE EXCEPTION für die Ausnahmeklasse CX_ABAP_AUTH_CHECK_EXCEPTION an. Versorgen Sie den Konstruktorparameter textid mit der öffentlichen Konstante missing_authorization dieser Ausnahmeklasse.

    1. Passen Sie den Quelltext wie folgt an:

      ABAP
      1234
      RAISE EXCEPTION TYPE cx_abap_auth_check_exception EXPORTING textid = cx_abap_auth_check_exception=>missing_authorization.
  5. Aktivieren und testen Sie Ihren Code. Passen Sie den Wert der Konstante c_carrier_id an, um die verschiedenen Ausnahmen zu provozieren.

    1. Drücken Sie Strg + F3, um den Quelltext zu aktivieren.

    2. Drücken Sie F9, um den Code als Konsolen-App auszuführen.

    3. Setzen Sie den Wert der Konstante c_carrier_id auf XX, um die Ausnahme für einen ungültigen Wert zu provozieren.

    4. Setzen Sie den Wert der Konstante c_carrier_id auf UA, um die Ausnahme für die fehlende Berechtigung zu provozieren.