Erste Schritte
Grundlegende Methoden und Konzepte anwenden
Mit lokalen Klassen arbeiten
Daten aus der Datenbank lesen
Mit strukturierten Datenobjekten arbeiten
Mit komplexen internen Tabellen arbeiten
Datenbankänderungen mit Business Objects implementieren
Das ABAP-RESTful-Anwendungsprogrammiermodell beschreiben

Kontrollstrukturen in ABAP verwenden

Objectives

After completing this lesson, you will be able to:
  • bedingte Verzweigung implementieren
  • Ausnahmen behandeln.
  • Iterationen implementieren.

Bedingte Verzweigungen

Eine bedingte Verzweigung ist eine Kontrollstruktur, mit der Sie die Ausführung von Quelltext von logischen Bedingungen abhängig machen können.

Die häufigste bedingte Verzweigung besteht aus einem Paar der Schlüsselwörter IF und ENDIF. Der Quelltextblock zwischen IF und ENDIF wird nur ausgeführt, wenn die Bedingung nach IF erfüllt ist.

Sie können weitere Quelltextblöcke hinzufügen, indem Sie die Struktur IF … ENDIF um maximal ein Schlüsselwort ELSE und eine beliebige Anzahl von Schlüsselwörtern ELSEIF erweitern. Durch das Hinzufügen des Schlüsselworts ELSE stellen Sie sicher, dass immer genau einer der Quelltextblöcke ausgeführt wird. Wenn ELSE fehlt, kann es vorkommen, dass keiner der Quelltextblöcke ausgeführt wird.

Der auszuführende Quelltextblock wird wie folgt ermittelt:

  • Zuerst wird die IF-Bedingung ausgewertet. Wenn diese erfüllt ist, wird der zugehörige Quelltextblock ausgeführt, und das Programm wird nach ENDIF fortgesetzt.
  • Nur wenn die IF-Bedingung nicht erfüllt ist, wird die Bedingung nach dem ersten ELSEIF ausgewertet. Wenn diese erfüllt ist, wird der zugehörige Quelltextblock ausgeführt, und das Programm wird nach ENDIF fortgesetzt.
  • Dies geschieht nacheinander für alle ELSEIF-Bedingungen. Wenn keine der Bedingungen erfüllt ist und die Struktur ELSE enthält, wird der Quelltextblock nach ELSE ausgeführt. Andernfalls wird keiner der Quelltextblöcke ausgeführt.

Hinweis

Im Gegensatz zu vielen anderen Programmiersprachen benötigt ABAP ein Trennzeichen (.) nach jeder der logischen Bedingungen und selbst nach dem Schlüsselwort ELSE.

Logische Bedingungen sind eine Kombination aus Vergleichen, logischen Operationen, Ausdrücken und Funktionen, die das Laufzeitsystem auswertet, um zu entscheiden, ob die Bedingung wahr oder falsch ist.

Der häufigste Anwendungsfall für logische Bedingungen ist nach den Schlüsselwörtern IF oder ELSEIF in einer „IF ... ENDIF."-Struktur.

Das erste Beispiel ist ein einfacher Vergleich: Die Bedingung ist wahr, wenn die beiden Datenobjekte x und y den gleichen Wert haben.

Das zweite Beispiel ist etwas differenzierter: Entweder ist der Wert von x größer oder gleich y und kleiner als das Doppelte des Werts von y oder er ist kleiner oder gleich y und größer als der doppelte Wert von y.

Das dritte Beispiel verwendet die arithmetische Funktion „abs( )" und den logischen Ausdruck „BETWEEN <Ausdruck1> AND <Ausdruck2>". Die Bedingung ist wahr, wenn der absolute Wert von x zwischen dem absoluten Wert von y und dem absoluten Wert von zweimal y liegt.

Für einfache Wertevergleiche können Sie die Operatoren =, <>, >, <, >= und <= verwenden. Sie können nicht nur die Werte von Datenobjekten vergleichen, sondern auch die Werte vieler anderer Ausdrücke, wie beim arithmetischen Ausdruck „2 * y" im Beispiel.

Notiz

ABAP verwendet das gleiche Symbol (=) für Wertzuweisungen und für Wertevergleiche. Die Unterscheidung erfolgt anhand der Position.

Sie können die Operatoren AND und OR verwenden, um logische Ausdrücke zu kombinieren, und den Operator NOT, um einen Ausdruck zu negieren. Ohne Klammern bindet NOT stärker als AND und AND stärker als OR.

ABAP kennt einige spezielle logische Ausdrücke:

  • <Datenobjekt> IS INITIAL ist wahr, wenn <Datenobjekt> seinen typgerechten Initialwert enthält
  • <Datenobjekt> IS NOT INITIAL ist wahr, wenn <Datenobjekt> einen Wert enthält, der vom typgerechten Initialwert abweicht
  • <Datenobjekt> BETWEEN <Ausdruck1> AND <Ausdruck2>

Einige spezielle ABAP-Funktionen sind Prädikatfunktionen. Dies bedeutet, dass sie selbst logische Bedingungen sind. „Contains( )" ist eine Funktion, die zeichenartige Werte vergleicht und „line_exists( )" führt eine Existenzprüfung für eine Zeile einer internen Tabelle durch.

Eine zweite Technik für bedingte Verzweigungen ist das CASE … WHEN .. ENDCASE Kontrollstruktur.

Bedingte Verzweigung mit CASE .. ENDCASE ist ein Spezialfall der allgemeineren Verzweigung mit IF … ENDIF. Sie können CASE in Situationen verwenden, in denen die Verzweigung vom Wert eines einzelnen Datenobjekts abhängt, das Sie nacheinander mit einer Reihe möglicher Werte vergleichen, indem Sie jedes Mal einen „Ist-gleich"-Vergleich verwenden.

Im Beispiel wird der Wert des Datenobjekts number mit den Werten 1 und 2 verglichen. Wenn der Wert gleich 1 ist, wird <code_block_1> ausgeführt, und wenn der Wert euqals 2 ist, wird stattdessen <code_blocl_2> ausgeführt. Bei jedem anderen Wert wird der Quelltextblock nach WHEN OTHERS ausgeführt.

Alle bedingten Verzweigungen mit CASE … ENDCASE könnten auch mit einer IF … ENDIF-Struktur implementiert werden. Dies wird durch das Beispiel auf der rechten Seite veranschaulicht.

Hinweis

Sie sollten CASE … ENDCASE verwenden, wenn Sie sich mit dem Sonderfall befassen, um die Lesbarkeit Ihres Quelltexts zu erhöhen.

Probieren Sie es aus: bedingte Verzweigung

  1. Legen Sie wie in der ersten Übung dieser Schulung eine neue globale Klasse an, die das Interface IF_OO_ADT_CLASSRUN implementiert.
  2. Kopieren Sie das folgende Code-Snippet in den Implementierungsteil der Methode if_oo_adt_classrun~main( ):
    Code Snippet
    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
    * Declarations ********************************************************************** CONSTANTS c_number TYPE i VALUE 0. * CONSTANTS c_number TYPE i VALUE 1. * CONSTANTS c_number TYPE i VALUE 2. * CONSTANTS c_number TYPE i VALUE -1. * CONSTANTS c_number TYPE i VALUE -2. * Example 1: Simple IF ... ENDIF. ********************************************************************** out->write( `--------------------------------` ). out->write( `Example 1: Simple IF ... ENDIF.` ). out->write( `-------------------------------` ). IF c_number = 0. out->write( `The value of C_NUMBER equals zero` ). ELSE. out->write( `The value of C_NUMBER is NOT zero` ). ENDIF. * Example 2: Optional Branches ELSEIF and ELSE ********************************************************************** out->write( `--------------------------------------------` ). out->write( `Example 2: Optional Branches ELSEIF and ELSE` ). out->write( `--------------------------------------------` ). IF c_number = 0. out->write( `The value of C_NUMBER equals zero` ). ELSEIF c_number > 0. out->write( `The value of C_NUMBER is greater than zero` ). ELSE. out->write( `The value of C_NUMBER is less than zero` ). ENDIF. * Example 3: CASE ... ENDCASE ********************************************************************** out->write( `---------------------------` ). out->write( `Example 3: CASE ... ENDCASE` ). out->write( `---------------------------` ). CASE c_number. WHEN 0. out->write( `The value of C_NUMBER equals zero` ). WHEN 1. out->write( `The value of C_NUMBER equals one` ). WHEN 2. out->write( `The value of C_NUMBER equals two` ). WHEN OTHERS. out->write( `The value of C_NUMBER equals non of the above` ). ENDCASE.
  3. Drücken Sie STRG + F3, um die Klasse zu aktivieren, und F9, um sie als Konsolen-App auszuführen.
  4. Analysieren Sie die Konsolenausgabe. Probieren Sie mit dem Quelltext Verschiedenes aus, um sich mit den Konzepten vertraut zu machen. Entkommentieren Sie verschiedene Deklarationen der Konstante c_number mit unterschiedlichen Werten, um festzustellen, welche Verzweigungen des Quelltexts ausgeführt werden.

Ausnahmebehandlung

Exceptions

In ABAP ist eine Ausnahme eine Fehlersituation bei der Ausführung eines ABAP-Programms. Der Quelltext, der die Fehlersituation erkennt, löst eine Ausnahme aus.

Je nachdem, wodurch die Ausnahme ausgelöst wird, wird zwischen Systemausnahmen und Anwendungsausnahmen unterschieden.

Ohne weitere Maßnahmen führen Ausnahmen zu Laufzeitfehlern. Ein Laufzeitfehler bricht das Programm ab. Er wird standardmäßig in einem Kurzdump dokumentiert.

Sie können den Laufzeitfehler vermeiden, wenn die betreffende Ausnahme behandelbar ist. Eine behandelbare Ausnahme kann im Programm mit den Anweisungen TRY … CATCH … ENDTRY behandelt werden.

Alle Anwendungsausnahmen und viele Systemausnahmen sind behandelbar. Später in diesem Kurs erfahren Sie, wie Sie Anwendungsausnahmen auslösen. An dieser Stelle konzentrieren wir uns auf die Behandlung behandelbarer Systemausnahmen.

Das folgende Video zeigt einige Beispiele für Laufzeitfehler.

Ausnahmebehandlung

Um zu verhindern, dass ein Programm aufgrund einer behandelbaren Ausnahme abgebrochen wird, muss der Quelltext, aus dem die Ausnahme stammt, mit den Anweisungen TRY und ENDTRY umgeben werden. Dadurch wird der Quelltext Teil des TRY-Blocks der TRY … ENDTRY-Struktur.

Vor der Anweisung ENDTRY müssen Sie eine CATCH-Anweisung hinzufügen, gefolgt von der ID der Ausnahme, die Sie behandeln möchten. Optional können Sie mehrere CATCH-Anweisungen hinzufügen, um mehrere verschiedene Ausnahmen zu behandeln. Auf jede CATCH-Anweisung muss Quelltext folgen, um diese Ausnahme zu behandeln. Dieser Quelltext wird als CATCH-Block bezeichnet.

Wenn die Programmausführung die TRY-Anweisung erreicht, wird mit dem Quelltext im TRY-Block fortgefahren. Dann können drei Dinge passieren:

  1. Wenn während des TRY-Blocks keine Ausnahme ausgelöst wird, werden die CATCH-Blöcke ignoriert. Die Ausführung wird nach der Anweisung ENDTRY fortgesetzt.
  2. Wenn während des TRY-Blocks eine Ausnahme ausgelöst wird, für die es ein passendes CATCH gibt, wird die Ausführung des TRY-Blocks beendet und der CATCH-Block für diese Ausnahme ausgeführt. Danach wird die Ausführung nach der Anweisung ENDTRY fortgesetzt.
  3. Wenn während des TRY-Blocks eine Ausnahme ausgelöst wird, für die kein passendes CATCH vorhanden ist, bricht das Programm mit einem Laufzeitfehler ab.

Nachdem Sie nun mehr über Ausnahmen erfahren haben, sehen wir uns an, wie Sie sie behandeln können.

Probieren Sie es aus: Ausnahmebehandlung

  1. Legen Sie wie in der ersten Übung dieser Schulung eine neue globale Klasse an, die das Interface IF_OO_ADT_CLASSRUN implementiert.
  2. Kopieren Sie das folgende Code-Snippet in den Implementierungsteil der Methode if_oo_adt_classrun~main( ):
    Code Snippet
    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
    * Declarations ********************************************************************** DATA result TYPE i. DATA numbers TYPE TABLE OF i. * Preparation ********************************************************************** APPEND 123 TO numbers. * Example 1: Conversion Error (no Number) ********************************************************************** CONSTANTS c_text TYPE string VALUE 'ABC'. * CONSTANTS c_text TYPE string VALUE '123'. out->write( `---------------------------` ). out->write( `Example 1: Conversion Error` ). out->write( `---------------------------` ). TRY. result = c_text. out->write( |Converted content is { result }| ). CATCH cx_sy_conversion_no_number. out->write( |Error: { c_text } is not a number!| ). ENDTRY. * Example 2: Division by Zero ********************************************************************** CONSTANTS c_number TYPE i VALUE 0. * CONSTANTS c_number TYPE i VALUE 7. out->write( `---------------------------` ). out->write( `Example 2: Division by Zero` ). out->write( `---------------------------` ). TRY. result = 100 / c_number. out->write( |100 divided by { c_number } equals { result }| ). CATCH cx_sy_zerodivide. out->write( `Error: Division by zero is not defined!` ). ENDTRY. * Example 3: Itab Error (Line Not Found) ********************************************************************** CONSTANTS c_index TYPE i VALUE 2. * CONSTANTS c_index TYPE i VALUE 1. out->write( `-------------------------` ). out->write( `Example 3: Line Not Found` ). out->write( `-------------------------` ). TRY. result = numbers[ c_index ]. out->write( |Content of row { c_index } equals { result }| ). CATCH cx_sy_itab_line_not_found. out->write( `Error: Itab has less than { c_index } rows!` ). ENDTRY. * Example 4: Combination of Different Exceptions ********************************************************************** * CONSTANTS c_char TYPE c LENGTH 1 VALUE 'X'. * CONSTANTS c_char TYPE c length 1 value '0'. CONSTANTS c_char TYPE c LENGTH 1 VALUE '1'. * CONSTANTS c_char TYPE c length 1 value '2'. out->write( `----------------------` ). out->write( `Example 4: Combination` ). out->write( `----------------------` ). TRY. result = numbers[ 2 / c_char ]. out->write( |Result: { result } | ). CATCH cx_sy_zerodivide. out->write( `Error: Division by zero is not defined` ). CATCH cx_sy_conversion_no_number. out->write( |Error: { c_char } is not a number! | ). CATCH cx_sy_itab_line_not_found. out->write( |Error: Itab contains less than { 2 / c_char } rows| ). ENDTRY.
  3. Drücken Sie STRG + F3, um die Klasse zu aktivieren, und F9, um sie als Konsolen-App auszuführen.
  4. Analysieren Sie die Konsolenausgabe. Probieren Sie mit dem Quelltext Verschiedenes aus, um sich mit dem Konzept vertraut zu machen:
    • Kommentieren Sie die Ausnahmebehandlung, damit das System einen Laufzeitfehler ausgibt.
    • Ändern Sie die Werte der Konstanten c_number, c_text, c_index und c_char so, dass keine Ausnahmen ausgelöst werden.

Iterationen

Iterationen sind Kontrollstrukturen, die einen mehrfach ausgeführten Quelltextblock definieren.

Die einfachste Form der Iteration besteht aus einem Quelltextblock, der von den beiden Anweisungen DO und ENDDO umgeben ist. Ohne weitere Maßnahmen entsteht eine Endlosschleife, die durch eine der folgenden Möglichkeiten vermieden werden muss:

Angegebene Anzahl von Iterationen

Durch Erweiterung der DO-Anweisung mit einem Integer-Ausdruck gefolgt vom Schlüsselwort TIMES kann explizit angegeben werden, wie oft der Quelltextblock iteriert werden soll. Der Integer-Ausdruck kann genauso einfach wie ein Zahlenliteral sein, aber auch arithmetische Berechnungen sind möglich. Wenn der Wert des Ausdrucks gleich 0 ist, wird der Quelltextblock zwischen DO und ENDDO überhaupt nicht ausgeführt, und das Programm fährt sofort mit dem Quelltext nach ENDDO fort.

Abbruch aufgrund einer logischen Bedingung

Sie können eine Iteration jederzeit mit der Anweisung EXIT abbrechen. Das Programm wird dann mit dem Quelltext nach ENDDO fortgesetzt. Beachten Sie, dass außerhalb von Iterationen EXIT eine andere Wirkung hat. Dort bricht die Anweisung die Verarbeitung des aktuellen Verarbeitungsblocks ab, z.B. der aktuellen Methode.

In der Regel ist EXIT von IF und ENDIF umgeben, um die Iteration abhängig von einer Abbruchbedingung abzubrechen. Beachten Sie, dass solche Iterationen in Endlosschleifen umgewandelt werden können, wenn die Abbruchbedingung nie wahr wird.

Natürlich ist es möglich, die beiden Methoden zu kombinieren, d.h., die Anzahl der Iterationen explizit anzugeben und dann die Iteration mit EXIT zu verlassen. Dadurch wird die Anzahl der Iterationen zu einer maximalen Anzahl, die zur Laufzeit möglicherweise nicht erreicht wird.

Basierend auf einer internen Tabelle

Eine dritte Art der Iteration ist die Struktur LOOP … ENDLOOP, mit der die Zeilen einer internen Tabelle nacheinander gelesen werden. Hier wird die Anzahl der Iterationen durch die Anzahl der Zeilen in der internen Tabelle bestimmt.

Im Quelltextblock zwischen DO und ENDDO können Lesezugriffe auf das eingebaute ABAP-Datenobjekt „sy-index" implementiert werden. Diese Integer-Variable dient als Iterationszähler, d.h., die ABAP-Laufzeit erhöht die Variable zu Beginn jeder neuen Iteration um eins.

Im Gegensatz zu anderen Programmiersprachen beginnt „sy-index" bei der ersten Iteration mit dem Wert 1.

Die eingebaute ABAP-Variable „sy-tabix" kann einen ähnlichen Zweck für Iterationen mit LOOP erfüllen. Beachten Sie jedoch, dass „sy-tabix" eigentlich kein Zähler ist, sondern die Position der Tabellenzeile identifiziert, die in der aktuellen Iteration verarbeitet wird. Später erfahren Sie mehr über den Unterschied, wenn nicht alle Zeilen einer internen Tabelle in einer „LOOP … ENDLOOP"-Struktur verarbeitet werden.

Probieren Sie es aus: Iterationen

  1. Legen Sie wie in der ersten Übung dieser Schulung eine neue globale Klasse an, die das Interface IF_OO_ADT_CLASSRUN implementiert.
  2. Kopieren Sie das folgende Code-Snippet in den Implementierungsteil der Methode if_oo_adt_classrun~main( ):
    Code Snippet
    12345678910111213141516171819202122232425262728293031323334353637383940414243
    * Declarations ********************************************************************** CONSTANTS c_number TYPE i VALUE 3. * CONSTANTS c_number TYPE i VALUE 5. * CONSTANTS c_number TYPE i VALUE 10. DATA number TYPE i. * Example 1: DO ... ENDDO with TIMES ********************************************************************** out->write( `----------------------------------` ). out->write( `Example 1: DO ... ENDDO with TIMES` ). out->write( `----------------------------------` ). DO c_number TIMES. out->write( `Hello World` ). ENDDO. * Example 2: DO ... ENDDO with Abort Condition ********************************************************************** out->write( `-------------------------------` ). out->write( `Example 2: With Abort Condition` ). out->write( `-------------------------------` ). number = c_number * c_number. " count backwards from number to c_number. DO. out->write( |{ sy-index }: Value of number: { number }| ). number = number - 1. "abort condition IF number <= c_number. EXIT. ENDIF. ENDDO.
  3. Drücken Sie STRG + F3, um die Klasse zu aktivieren, und F9, um sie als Konsolen-App auszuführen.
  4. Analysieren Sie die Konsolenausgabe. Probieren Sie mit dem Quelltext Verschiedenes aus, um sich mit den Konzepten vertraut zu machen. Entkommentieren Sie verschiedene Deklarationen der Konstante c_number, um festzustellen, wie sich die verschiedenen Werte auf das Ergebnis auswirken.