Using Control Structures in ABAP

Objectives

After completing this lesson, you will be able to:

  • Implement conditional branching
  • Handle Exceptions
  • Implement Iterations

Conditional Branching

A conditional branching is a control structure that allows you to make the execution of code dependent on logical conditions.

The most common conditional branching consists of a pair of keywords IF and ENDIF. The code block between IF and ENDIF is only executed, if the condition after IF is fulfilled.

You can add more code blocks by extending the IF … ENDIF structure with up to one keyword ELSE and an arbitrary number of keywords ELSEIF. By adding keyword ELSE you ensure that always exactly one of the code blocks is executed. If ELSE is missing it can happen that none of the code blocks is executed.

The code block to be executed is determined as follows:

  • First, the IF condition is evaluated. If it is fulfilled, the related code block is executed and the program continues after ENDIF.
  • Only if the IF condition is not fulfilled, the condition after the first ELSEIF is evaluated. If it is fulfilled, the related code block is executed and the program continues after ENDIF.
  • This is done consecutively for all ELSEIF conditions. If none of the conditions is fulfilled and the structure contains ELSE, the code block after ELSE is executed. Otherwise the none of the code blocks is executed.
Hint
As opposed to many other programming languages, ABAP requires a delimiter (.) after each of the logical conditions and even after keyword ELSE.

Logical conditions are a combination of comparisons, logical operations, expressions and functions that the runtime system evaluates to decide whether the condition is true or false.

The most common use-case for logical conditions is after keywords IF or ELSEIF in an IF ... ENDIF. structure.

The first example is a simple comparison: The condition is true if the two data objects x and y have the same value.

The second example is a bit more sophisticated: Either the value of x is greater than or equal to y and less than twice the value of y or it is less than or equal to y and greater than twice the value of y.

The third example makes use of arithmetic function abs( ) and logical expression BETWEEN <expression1> AND <expression2> . The condition is true if the absolute value of x lies between the absolute value of y and the absolute value of two times y.

For simple value comparisons you can use operators =, <>, >, <, >=, and <=. You can not only compare the values of data objects, but the values of many other expressions, like the arithmetic expression 2 * y in the example.

Note
ABAP uses the same symbol (=) for value assignments and for value comparisons. The distinction is made based on the position.

You can use operators AND and OR to combine logical expressions and operator NOT to negate an expression. Without brackets, NOT binds stronger than AND and AND stronger than OR.

ABAP knows some special logical expressions:

  • <data object> IS INITIAL is true if <data object> contains its type-specific initial value
  • <data object> IS NOT INITIAL is true if <data object> contains a value that is different from the type-specific initial value
  • <data object> BETWEEN <expression1> AND <expression2>

Some special ABAP functions are predicate functions. This means that they are logical conditions themselves. Contains( ) is a function that compares character-like values and line_exists( ) performs an existence check for a row in an internal table.

A second technique for conditional branching is the CASE … WHEN .. ENDCASE control structure.

Conditional branching with CASE .. ENDCASE is a special case of the more general branching with IF … ENDIF. You can use CASE in situations where the branching depends on the value of a single data object, which you consecutively compare to a set of possible values, using an equals comparison each time.

In the example, the value of data object number is compared to values 1 and 2. If the value equals 1, <code_block_1> is executed and if the value euqals 2, <code_blocl_2> is executed instead. For any other value, the code block after WHEN OTHERS is executed.

Any conditional branching with CASE … ENDCASE could be implemented with an IF … ENDIF structure, as well. This is illustrated with the example on the right.

Hint
You should use CASE … ENDCASE when dealing with the special case to increase readability of your code.

Try It Out: Conditional Branching

  1. Like in the first exercise of this course, create a new global class that implements interface IF_OO_ADT_CLASSRUN.
  2. Copy the following code snippet to the implementation part of method if_oo_adt_classrun~main( ):
    Code snippet
    
    * 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. 
    
    Expand
  3. Press CTRL + F3 to activate the class and F9 to execute it as a console app.
  4. Analyze the console output. Play around with the source code to get familiar with the concepts; Uncomment different declarations of constant c_number with different values to see, which branches of the code get executed.

Exception Handling

Exceptions

In ABAP, an exception is an error situation during execution of an ABAP program. An exception is raised by the code that detects the error situation.

Depending on who raises the exception, we distinguish between system exceptions and application exceptions.

Without further measures exceptions result in runtime errors. A runtime error terminates the program and is documented by default in a short dump.

You can avoid the runtime error if the exception in question is catchable. A catchable exception can be treated in the program using statements TRY … CATCH … ENDTRY.

All application exceptions and many system exceptions are catchable. Later in this course you will learn how to raise application exceptions. At this point we will focus on the handling of catchable system exceptions.

The following video shows some examples of runtime errors.

Exception Handling

To prevent a program from terminating because of a catchable exception, you have to surround the code from where the exception originates with statements TRY and ENDTRY. By doing so, the code becomes part of the TRY block of the TRY … ENDTRY structure.

Before the ENDTRY statement you have to add a CATCH statement followed by the ID of the exception you want to handle. Optionally, you can add more than one CATCH statement to handle several different exceptions. Each CATCH statement should be followed by code to handle this exception. This code is called the CATCH block.

When program execution reaches the TRY statement, it continues with the code in the TRY block. Three things can happen then:

  1. If no exception is raised during the TRY block, the CATCH blocks are ignored. Execution continues after the ENDTRY statement.
  2. If an exception is raised during the TRY block, for which a matching CATCH exists, execution of the TRY block is terminated and the CATCH block for this exception is executed. Afterward, execution continues after the ENDTRY statement.
  3. If an exception is raised during the TRY block for which no matching CATCH exists, the program terminates with a runtime error.

Now that you have learned about exceptions, let's see how you can handle them.

Try It Out: Exception Handling

  1. Like in the first exercise of this course, create a new global class that implements interface IF_OO_ADT_CLASSRUN.
  2. Copy the following code snippet to the implementation part of method if_oo_adt_classrun~main( ):
    Code snippet
    
    * 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.
    
    Expand
  3. Press CTRL + F3 to activate the class and F9 to execute it as a console app.
  4. Analyze the console output. Play around with the source code to get familiar with the concept:
    • Comment the exception handling to make the system raise a runtime error.
    • Change the values of constants c_number, c_text, c_index, and c_charin a way that no exceptions are raised.

Iterations

Iterations are control structures that define a block of code which is executed several times.

The simplest form of iteration consists of a code block surrounded by pair of statements DO and ENDDO. Without further measures this establishes an endless loop which must be avoided by one of the following possibilities:

Specified number of iterations

By extending the DO statement with an integer expression followed by keyword TIMES, you can specify explicitly how often the code block is to be iterated. The integer expression can be as simple as number literal, but also arithmetic calculations are an option. If the value of the expression equals 0, the code block between DO and ENDDO is not executed at all and the program immediately continues with the code after ENDDO.

Abort based on a logical condition

You can abort an iteration any time using the EXIT statement. The program then continues with the code after ENDDO. Be aware that outside of iterations EXIT has a different effect. There it terminates the processing of the current processing block, for example the current method.

Usually, EXIT is surrounded by IF and ENDIF to terminate the iteration depending on an abort condition. Be aware that such iterations can turn into endless loops, if the abort condition never gets true.

Of course it is possible to combine the two techniques, that is, explicitly specify the number of iterations and then leave the iteration with EXIT. Thus the number of iterations becomes a maximum number that might not be reached at runtime.

Based on an internal table

A third type of iteration is the LOOP … ENDLOOP structure that is used to consecutively read the rows of an internal table. Here, the number of iterations is determined by the number of rows in the internal table.

In the code block between DO and ENDDO, you can implement read-accesses to ABAP built-in data object sy-index. This integer variable serves as an iteration counter, that is, the ABAP runtime increases it by one at the beginning of each new iteration.

In contradiction to what you might be used to from other programming languages, sy-index starts with value 1 during the first iteration.

ABAP built-in variable sy-tabix can fulfill a similar purpose for iterations with LOOP. But be aware that strictly speaking sy-tabix is not really a counter but it identifies the position of the table row that is processed in the current iteration. Later we will see the difference when not all rows of an internal table are processed in a LOOP … ENDLOOP structure.

Try It Out: Iterations

  1. Like in the first exercise of this course, create a new global class that implements interface IF_OO_ADT_CLASSRUN.
  2. Copy the following code snippet to the implementation part of method if_oo_adt_classrun~main( ):
    Code snippet
    
    * 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.
    
    Expand
  3. Press CTRL + F3 to activate the class and F9 to execute it as a console app.
  4. Analyze the console output. Play around with the source code to get familiar with the concepts; Uncomment different declarations of constant c_number to see how the different values affect the result.

Log in to track your progress & complete quizzes