Defining And Calling Methods

Objectives
After completing this lesson, you will be able to:

After completing this lesson, you will be able to:

  • Define and call methods

Defining Methods

As an example, add two methods to our class lcl_connection.

A set_attributes( ) method to set the values for attribute i_carrier_id and i_connection_id and a get_attributes( ) method to return the values of these attributes. Where set_attributes( ) needs two importing parameters, one for each of attribute, the get_attributes( ) method needs two exporting parameters.

For every method that you define, you must also create an implementation in the implementation part of the class. Until you do so, you see syntax errors in your class; the syntax check tells you that the implementation of the method is missing.

Hint
ADT offers a quickfix to add the missing implementation. To use this quick fix, proceed as follows:
  1. Position the cursor in a METHODS statement with an error and press Ctrl + 1.
  2. From the list of possible quick fixes choose Add implementation for … and press Enter . If the implementation is missing for several methods, the quickfix title reads Add … unimplemented methods.

How to Define Methods

Implementing Methods

You must implement every method that you define. You do this in the implementation part of the class, by adding a pair of statements METHOD <method_name> and ENDMETHOD.

The method implementation contains ABAP statements that can access the parameters of the method (you are not allowed to change importing parameters) and all types, attributes, and constants that you declared in the class, independent from their visibility. Instance methods may access both instance attributes and static attributes. Static methods may only access static components.

Inside the implementation part of a class, you can access the attributes of that class without a reference variable and '->' (or the class name and '=>' , in case of static attributes).

Only in the implementation of instance methods, ABAP offers built-in variable ME. ME is a reference variable, typed with the current class and filled at runtime with the address of the current instance. The use of ME is optional and should be avoided, unless the name of an attribute collides with the name of another data object, for example a parameter name.

In the example, the import parameters of method set_attributes( ) have the same names as the corresponding attributes. In such a situation, the name by itself denotes the parameter. Only by putting me-> in front it becomes clear that an attribute of the current instance is to be accessed.

If an error occurs during the execution of a method, the method can trigger an exception using statement RAISE EXCEPTION TYPE, followed by the name of the exception.

Note
Technically, exception names are the names of special ABAP classes and statement RAISE EXCEPTION TYPE creates an instance of the referenced class. The instance is referred to as exception object and the special kind of ABAP classes are called exception classes.

The moment an exception is raised, the method execution is terminated.

Control is returned to the calling program if all prerequisites are met. Otherwise the entire program terminates with a runtime error.

The prerequisites for continuing the program are as follows:

  • The raised exception is declared in the RAISING clause of the method signature
  • The method call is surrounded by a TRY … ENDTRY control structure
  • The TRY … ENDTRY control structure contains a CATCH block for the exception
Note
For some exceptions, the ABAP editor displays a syntax warning with a quick fix when you raise an exception that is not yet declared in the RAISING clause of the method.

How to Implement Methods

Calling Methods

You call an instance method using a reference variable and the instance component selector (->). The component selector is followed by the name of the method you want to call. For static methods you use the class name and the static component selector (=>). On both cases, the parameter passing takes place in a pair of brackets. The brackets are needed in any case. They remain empty if no parameters are to be passed.

Note
No blank is allowed between the method name and the opening bracket. On the other hand you need at least one blank after the opening bracket and before the closing bracket.

Importing parameters are listed after keyword EXPORTING because the values that are imported by the called method are exported by the calling program. The parameter names are listed on the left-hand side of an equals sign (=) and an expression on the right-hand side.. This expression can be as simple as a literal, constant, or variable but any other expressions are also allowed as long as the type of the expression matches the type of the parameter.

Exporting parameters are listed after keyword IMPORTING. Note, that for exporting parameter the parameter name is also listed on the left-hand side of the equals sign. The variable on the right-hand side has to have the same type as the parameter.

Changing parameters are listed after keyword CHANGING. The type of the variable on the right-hand side has to match the type of the parameter on the left hand side.

The example illustrates the call of instance methods set_attributes( ) and get_attributes( ). The parameter names are always on the left-hand side of the equals sign (=).

Hint

You can use code completion in ADT to generate the method call including the parameter passing. To do so, proceed as follows:

  1. Type in the reference variable (or class name) and the component selector.
  2. Once you typed the component selector press Ctrl + Space to display a list of components you can address.
  3. If you choose a method, and press Shift + Enter to insert the name of the method and its full signature into your code. Optional parameters are listed in comment lines.

When calling a method, keyword IMPORTING is always needed to receive the value of exporting parameters. But keyword EXPORTING becomes optional, if you only want to supply importing parameters.

For methods with only one mandatory importing parameter, you can even omit the explicit parameter assignment. In the example, parameter i_carrier_id is optional with default value 'LH'. Therefore the value between the brackets is assigned to the remaining mandatory importing parameter i_connection_id.

How to Call Methods

Raising Exceptions

In a previous section of this class, you learned how to handle runtime errors with TRY … ENDTRY control structures.

Exceptions declared in the RAISING clause of a method definition are handled in exactly the same way:

  • Place the method call in the TRY-block of the TRY … ENDTRY control structure.
  • Define a CATCH block with the name of the exception you want to handle.
Note
If there is code that you want to skip in case the method call failed, you can place this code inside the try block, after the method call.

Try It Out: Method Calls and 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
    
        CONSTANTS c_carrier_id TYPE /dmo/carrier_id       VALUE 'LH'.
        CONSTANTS c_connection_id TYPE /dmo/connection_id VALUE '0400'.
    
        DATA connection  TYPE REF TO lcl_connection.
        DATA connections  TYPE TABLE OF REF TO lcl_connection.
    
    * Create Instance
    **********************************************************************
    
        connection = NEW #(  ).
    
    * Call Method and Handle Exception
    **********************************************************************
        out->write(  |i_carrier_id    = '{ c_carrier_id }' | ).
        out->write(  |i_connection_id = '{ c_connection_id }'| ).
    
        TRY.
            connection->set_attributes(
              EXPORTING
                i_carrier_id    = c_carrier_id
                i_connection_id = c_connection_id
            ).
    
            APPEND connection TO connections.
            out->write( `Method call successful` ).
          CATCH cx_abap_invalid_value.
            out->write( `Method call failed`     ).
        ENDTRY.  
    
    Copy code
  3. Navigate to tab Local Typesand insert the following code snippet there:
    Code snippet
    
    CLASS lcl_connection DEFINITION.
      PUBLIC SECTION.
    
    * Attributes
        DATA carrier_id    TYPE /dmo/carrier_id.
        DATA connection_id TYPE /dmo/connection_id.
    
    * Methods
        METHODS set_attributes
          IMPORTING
            i_carrier_id    TYPE /dmo/carrier_id  DEFAULT 'LH'
            i_Connection_id TYPE /dmo/connection_id
          RAISING
            cx_abap_invalid_value.
    
    
    ENDCLASS.
    
    CLASS lcl_connection IMPLEMENTATION.
    
      METHOD set_attributes.
    
        IF i_carrier_id IS INITIAL OR i_connection_id IS INITIAL.
          RAISE EXCEPTION TYPE cx_abap_invalid_value.
        ENDIF.
    
        carrier_id    = i_carrier_id.
        connection_id = i_connection_id.
    
      ENDMETHOD.
    
    ENDCLASS.
    
    Copy code
  4. Press CTRL + F3 to activate the class and F9 to execute it as a console app.
  5. Analyze the console output. Debug the program, play around with the source code to get familiar with the concepts. In particular, change the values of the two constants to debug the raising of the exception.

Functional Methods

Methods that have a returning parameter are called functional methods. It is not possible to define more than one returning parameter for the same method. It is mandatory that you define the returning parameter in the form VALUE(<parameter_name>). Besides the returning parameter a functional method can have any combination of other parameters. It is most common however, to add importing parameters only. The reason is, that with additional exporting or changing parameters you loose the biggest advantage of functional methods, namely, that you can use the result of a functional method directly in other ABAP expressions.

The figure shows two examples of how you can use functional methods in expressions; the first is a simple example in which the returning parameter is assigned directly to a variable. The second example shows how the call of the functional method is used as input for another method. The system executes the functional method, and then uses the value of the returning parameter as input for method write( ).

Try It Out: Functional Methods

  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
    
       DATA connection  TYPE REF TO lcl_connection.
        DATA connections  TYPE TABLE OF REF TO lcl_connection.
    
    * Create Instance
    **********************************************************************
    
        connection = NEW #(  ).
    
        connection->set_attributes(
          EXPORTING
            i_carrier_id    = 'LH'
            i_connection_id = '0400'
        ).
    
        APPEND connection TO connections.
    
    * Calling Functional Method
    **********************************************************************
        " in a value assignment (with inline declaration for result)
        DATA(result) = connection->get_output( ).
    
        " in logical expression
        IF connection->get_output(  ) IS NOT INITIAL.
    
          " as operand in a statement
          LOOP AT connection->get_output(  ) INTO DATA(line).
    
          ENDLOOP.
    
          "  to supply input parameter of another method
          out->write( data = connection->get_output( )
                      name = `  ` ).
    
        ENDIF.
    
    Copy code
  3. Navigate to tab Local Typesand insert the following code snippet there:
    Code snippet
    
    CLASS lcl_connection DEFINITION.
      PUBLIC SECTION.
    
    * Attributes
        DATA carrier_id    TYPE /dmo/carrier_id.
        DATA connection_id TYPE /dmo/connection_id.
    
    * Methods
        METHODS set_attributes
          IMPORTING
            i_carrier_id    TYPE /dmo/carrier_id  DEFAULT 'LH'
            i_Connection_id TYPE /dmo/connection_id.
    
        " Functional Method
        METHODS get_output
          RETURNING VALUE(r_output) TYPE string_table.
    
    *  PROTECTED SECTION.
    
    *  PRIVATE SECTION.
    
    ENDCLASS.
    
    CLASS lcl_connection IMPLEMENTATION.
    
      METHOD set_attributes.
    
        carrier_id    = i_carrier_id.
        connection_id = i_connection_id.
    
      ENDMETHOD.
    
      METHOD get_output.
    
        APPEND |------------------------------| TO r_output.
        APPEND |Carrier:     { carrier_id    }| TO r_output.
        APPEND |Connection:  { connection_id }| TO r_output.
    
      ENDMETHOD.
    
    ENDCLASS.
    
    Copy code
  4. Press CTRL + F3 to activate the class and F9 to execute it as a console app.
  5. Analyze the console output. Debug the program, play around with the source code to get familiar with the concepts. In particular, debug the different calls of functional method get_output( )..

Define and Call Methods

Task 1: Preparation

Steps

  1. If you finished the previous exercise Create and Manage Instances, create a copy of your global class ZCL_##_INSTANCES, and name the copy ZCL_##_METHODS, where ## is your group number. Then skip the rest of this task.

    1. In the Project Explorer view on the left, expand your package.

    2. Expand node Source Code LibraryClasses

    3. Right-click the name of the class you want to copy and choose Duplicate.

    4. In the Name field, enter the name ZCL_##_METHODS, where ## is your group number.

    5. Choose Next.

    6. Select your transport request and choose Finish.

  2. If you did not finish the previous exercise, create a new global class ZCL_##_METHODS, where ## is your group number. Ensure that the class implements the interface IF_OO_ADT_CLASSRUN.

    1. Choose FileNewABAP Class.

    2. Enter the name of your package in the Package field. In the Name field, enter the name ZCL_##_METHODS, where ## is your group number. Enter a description.

    3. In the Interfaces group box, choose Add.

    4. Enter IF_OO_ADT_CLASSRUN. When the interface appears in the hit list, double-click it to add it to the class definition.

    5. Choose Next.

    6. Select your transport request and choose Finish.

  3. Copy the following code between METHOD if_oo_adt_classrun~main. and ENDMETHOD. on the Global Class tab:

    Code snippet
    
        DATA connection TYPE REF TO lcl_connection.
        DATA connections TYPE TABLE OF REF TO lcl_connection.
    
    * First Instance
    **********************************************************************
    
        connection = NEW #(  ).
    
        connection->carrier_id    = 'LH'.
        connection->connection_id = '0400'.
    
        APPEND connection TO connections.
    
    * Second Instance
    **********************************************************************
    
        connection = NEW #(  ).
    
        connection->carrier_id    = 'AA'.
        connection->connection_id = '0017'.
    
        APPEND connection TO connections.
    
    * Third Instance
    **********************************************************************
    
        connection = NEW #(  ).
    
        connection->carrier_id    = 'SQ'.
        connection->connection_id = '0001'.
    
        APPEND connection TO connections.
    
    Copy code
    1. Navigate to the Global Class tab and insert the source code between METHOD if_oo_adt_classrun~main. and ENDMETHOD..

  4. Copy the following code to the Local Types tab:

    Code snippet
    
    CLASS lcl_connection DEFINITION.
    
    
    PUBLIC SECTION.
    
    
    DATA carrier_id    TYPE /dmo/carrier_id.
    DATA connection_id TYPE /dmo/connection_id.
    
    
    CLASS-DATA conn_counter TYPE i.
    
    
    PROTECTED SECTION.
    PRIVATE SECTION.
    
    
    ENDCLASS.
    
    
    CLASS lcl_connection IMPLEMENTATION.
    
    
    ENDCLASS.
    
    Copy code
    1. Navigate to the Local Types tab and insert the source code.

Task 2: Define Methods

Steps

  1. Switch to the local class lcl_connection.

    1. In the global class, choose Local Types.

  2. Add a method get_output to the public section of the class. It should have one returning parameter r_outputof global table typeSTRING_TABLE.

    Note
    Remember to surround the name of the returning parameter with VALUE( ).
    1. Enter the following code before the PROTECTED SECTION statement:

      Code snippet
      
      METHODS get_output 
           RETURNING
                VALUE(r_output) TYPE STRING_TABLE.
      Copy code
      Note
      For the moment, ignore syntax error Implementation missing for method "GET_OUTPUT".
  3. Add a method set_attributes to the public section of the class. It should have one importing parameter for each instance attribute of the class. Use the same types for the parameters that you used to type the attributes. To distinguish the parameters from the attributes, add prefix i_ to the parameter names. In addition, the method should raise exception CX_ABAP_INVALID_VALUE.

    1. Enter the following code before the PROTECTED SECTION statement:

      Code snippet
      
         METHODS set_attributes 
             IMPORTING
                i_carrier_id    TYPE /dmo/carrier_id 
                i_connection_id TYPE /dmo/connection_id
             RAISING
                cx_abap_invalid_value. 
      
      Copy code
      Note
      For the moment, ignore syntax error Implementation missing for method "SET_ATTRIBUTES".

Task 3: Implement Methods

Steps

  1. Use a quick fix to add the method implementations to the class.

    1. Position the cursor on the name of one of the methods in the editor and press Ctrl + 1.

    2. Double-click the suggestion Add 2 unimplemented methods.

  2. Implement method get_output. Append some string templates to returning parameter r_output. In the string templates, use embedded expressions to add the values of attributes carrier_id and connection_id.

    1. In the local class add the following code between the statements METHOD get_output. and ENDMETHOD.

      Code snippet
      
          APPEND |------------------------------| TO r_output.
          APPEND |Carrier:     { carrier_id    }| TO r_output.
          APPEND |Connection:  { connection_id }| TO r_output.
      
      Copy code
  3. Implement method set_attributes. If either of the two importing parameters is empty (IS INITIAL), raise exception CX_ABAP_INVALID_VALUE. Otherwise, fill the two instance attributes with the values of the importing parameters.

    1. In the local class add the following code between the statements METHOD set_attributes. and ENDMETHOD.

      Code snippet
      
      IF i_carrier_id IS INITIAL OR i_connection_id IS INITIAL.
         RAISE EXCEPTION TYPE cx_abap_invalid_value.
      ENDIF.
      
      carrier_id    = i_carrier_id. 
      connection_id = i_connection_id.
      
      Copy code
  4. Activate your class.

    1. Choose Ctrl + F3 to activate the class.

Task 4: Call a Functional Method

Steps

  1. Switch to the implementation of method if_oo_adt_classrun~main( ) in the global class.

    1. In the global class, choose Global Class scroll down to the implementation of method if_oo_adt_classrun~main( ).

  2. At the end of the method, add a loop over internal table connectionswith reference variable connection as work area.

    1. Add the following code before ENDMETHOD..

      Code snippet
      
         LOOP AT connections INTO connection.
      
         ENDLOOP.
      
      Copy code
  3. In the loop, call functional method get_output( ) for each instance in turn and write the result to the console.

    Hint
    You can use the call of method get_output( ) directly as input for out->write( ).
    1. Add the following code between LOOP AT connections INTO connection and ENDLOOP.

      Code snippet
      
      LOOP AT connections INTO connection.
        
        out->write( connection->get_output( ) ).
      
         ENDLOOP.
      
      Copy code
  4. Activate the class. Execute it as console app and analyze the console output.

    1. Press Ctrl + F3 to activate the class.

    2. Press F9 to run the class.

    3. Analyze the output on the Console window.

Task 5: Use Code Completion And Handle Exceptions

Steps

  1. For the first instance of class lcl_connection, replace the direct access to attributes carrier_id and connection_idwith a call of instance method set_attributes( ). Use code completion to insert the full signature of the method.

    Hint
    Press Ctrl + Space after you typed the component select (->) to display a list of available attributes and methods. Choose the method and then press Shift + Enter to insert the full signature of the method.
    1. Place the cursor in the next line after the first connection = NEW #( )..

    2. Type connection-> and press Ctrl + Space.

    3. Choose set_attributes and press Shift + Enter.

    4. Pass values to the importing parameters. Use the same literals that you previously used to set the attributes of this instance.

    5. Remove or comment the direct access to the instance attributes for this instance.

  2. Handle the exception. Surround the method call with TRY. and ENDTRY.. Add a CATCH-Block to handle exception CX_ABAP_INVALID_VALUE. Make sure the new instance is only added to internal table connections if the method call was successful.

    1. Uncomment the generated code line CATCH cx_abap_invalid_value. .

    2. Add TRY. before the method call .

    3. Add ENDTRY. after the CATCH statement.

    4. Between the CATCH statement and the ENDTRY statement add out->write( `Method call failed` ).

    5. Move the APPEND statement up to between the method call and CATCH statement.

    6. The complete method call should now look like this:

      Code snippet
      
      TRY.
              connection->set_attributes(
                EXPORTING
                  i_carrier_id    = 'LH'
                  i_connection_id = '0400'
              ).
      
              APPEND connection TO connections.
      
            CATCH cx_abap_invalid_value.
              out->write( `Method call failed` ).
          ENDTRY.
      
      *    connection->carrier_id    = 'LH'.
      *    connection->connection_id = '0400'. 
      *    APPEND connection TO connections. 
      
      
      Copy code
  3. Repeat the previous step for the other two instances of class lcl_connection.

    1. After this step, the implementation of method if_oo_adt_classrun~main( ) should read as follows:

      Code snippet
      
      DATA connection TYPE REF TO lcl_connection.
          DATA connections TYPE TABLE OF REF TO lcl_connection.
      
      * First Instance
      **********************************************************************
          connection = NEW #(  ).
      
          TRY.
              connection->set_attributes(
                EXPORTING
                  i_carrier_id    = 'LH'
                  i_connection_id = '0400'
              ).
      
              APPEND connection TO connections.
      
            CATCH cx_abap_invalid_value.
              out->write( `Method call failed` ).
          ENDTRY.
      
      *    connection->carrier_id    = 'LH'.
      *    connection->connection_id = '0400'.
      *    APPEND connection TO connections.
      
      * Second instance
      **********************************************************************
      
          connection = NEW #(  ).
      
          TRY.
              connection->set_attributes(
                EXPORTING
                  i_carrier_id    = 'AA'
                  i_connection_id = '0017'
              ).
      
              APPEND connection TO connections.
      
            CATCH cx_abap_invalid_value.
              out->write( `Method call failed` ).
          ENDTRY.
      
      *    connection->carrier_id    = 'AA'.
      *    connection->connection_id = '0017'.
      *    APPEND connection TO connections.
      
      * Third instance
      **********************************************************************
          connection = NEW #(  ).
      
          TRY.
              connection->set_attributes(
                EXPORTING
                  i_carrier_id    = 'SQ'
                  i_connection_id = '0001'
              ).
      
              APPEND connection TO connections.
      
            CATCH cx_abap_invalid_value.
              out->write( `Method call failed` ).
          ENDTRY.
      
      *    connection->carrier_id    = 'SQ'.
      *    connection->connection_id = '0001'.
      *
      *    APPEND connection TO connections.
      
      
      * Output
      **********************************************************************
      
          LOOP AT connections INTO connection.
      
            out->write( connection->get_output( ) ).
      
          ENDLOOP.
      
        ENDMETHOD.
      
      Copy code
  4. Activate the class. Execute it and debug the method calls.

    1. Press Ctrl + F3 to activate the class.

    2. Press F9 to run the class.

Save progress to your learning plan by logging in or creating an account