ABAP에서 제어 구조(Control Structure) 사용

Objectives

After completing this lesson, you will be able to:
  • 조건부 분기를 구현합니다.
  • 예외 처리.
  • 반복 구현 액티비티를 엽니다.

조건부 분기

조건부 분기는 논리 조건에 따라 코드를 실행할 수 있는 제어 구조입니다.

가장 일반적인 조건부 분기는 한 쌍의 키워드 IF와 ENDIF 로 구성됩니다. IF와 ENDIF 사이의 코드 블록은 IF 후의 조건이 충족되는 경우에만 실행됩니다.

IF … ENDIF 구조를 최대 하나의 키워드 ELSE 및 임의의 수의 키워드 ELSEIF로 확장하여 코드 블록을 더 추가할 수 있습니다. 키워드 ELSE를 추가하면 항상 코드 블록 중 하나만 실행되게 할 수 있습니다. ELSE가 누락된 경우 어떤 코드 블록도 실행되지 않을 수 있습니다.

실행할 코드 블록은 다음과 같이 결정됩니다.

  • 먼저 IF 조건이 평가됩니다. 이 조건이 충족되면 관련 코드 블록이 실행되고 프로그램이 ENDIF 후에 계속됩니다.
  • IF 조건이 충족되지 않은 경우에만 첫 번째 ELSEIF 뒤의 조건이 평가됩니다. 이 조건이 충족되면 관련 코드 블록이 실행되고 프로그램이 ENDIF 후에 계속됩니다.
  • 이는 모든 ELSEIF 조건에 대해 연속적으로 수행됩니다. 조건이 충족되지 않고 구조에 ELSE가 포함되어 있으면 ELSE 뒤의 코드 블록이 실행됩니다. 그렇지 않으면 코드 블록이 실행되지 않습니다.

힌트

다른 많은 프로그래밍 언어와 달리 ABAP에는 각 논리 조건 뒤에 구분 기호(.)가 필요하며 키워드 ELSE 다음도 필요합니다.

논리 조건은 런타임 시스템에서 평가하여 조건이 참 또는 거짓인지 여부를 결정하는 비교, 논리 작업, 표현식 및 함수의 조합입니다.

논리 조건의 가장 일반적인 사용 케이스는 IF ... ENDIF. 구조

첫 번째 예는 단순 비교입니다. 두 개의 데이터 오브젝트 x와 y가 동일한 값을 갖는 경우 조건이 참입니다.

두 번째 예는 좀 더 정교하다: x의 값이 y보다 크거나 같고 y의 두 배 미만이거나 y보다 작거나 같고 y보다 두 배 더 큽니다.

세 번째 예에서는 산술 함수 abs( )와 논리식 BETWEEN <식 1> AND <식 2>을 사용합니다. x의 절대값이 y의 절대값과 두 배 y의 절대값 사이에 있으면 조건이 참입니다.

단순 값 비교에는 =, <>, >, <, >=, <= 연산자를 사용할 수 있습니다. 데이터 오브젝트의 값을 비교할 수 있을 뿐만 아니라, 예시의 산술식 2 * y와 같은 다른 여러 표현식의 값을 비교할 수 있습니다.

노트

ABAP에서는 값 지정과 값 비교에 동일한 기호(=)를 사용합니다. 포지션은 포지션을 기준으로 구분됩니다.

연산자 AND와 OR을 사용하여 논리식과 NOT 연산자를 결합하여 표현식을 무효화할 수 있습니다. 괄호가 없으면 NOT 바인딩이 OR보다 AND와 AND보다 강합니다.

ABAP에는 다음과 같은 특수 논리식이 있습니다.

  • <data object> 에 해당 유형별 초기 값이 포함된 경우 IS INITIAL 이 true
  • <data object> 에 유형별 초기 값과 다른 값이 포함된 경우, IS NOT INITIAL이 참입니다.
  • <data object> BETWEEN <식 1> AND <식 2>

일부 특수 ABAP 함수는 술어 함수입니다. 즉, 논리 조건 자체입니다. Contains( )는 문자형 값을 비교하는 함수이며 line_exists( )는 내부 테이블의 행에 대한 존재 여부 확인을 수행합니다.

조건부 분기를 위한 두 번째 기법은 CASE … WHEN .. ENDCASE 제어 구조

CASE를 사용한 조건부 분기.. ENDCASE 는 IF … ENDIF 를 사용하여 보다 일반적인 분기를 수행하는 특별한 경우입니다. 분기마다 등가 비교를 사용하여 연속적으로 가능한 값 세트와 비교하는 단일 데이터 오브젝트의 값에 따라 분기가 결정되는 상황에서는 CASE 를 사용할 수 있습니다.

이 예에서 데이터 오브젝트 번호 의 값은 값 1 과 2 와 비교됩니다. 값이 1 이면 <code_block_1> 이 실행되고 euqals 2 값이 대신 <code_blocl_2> 가 실행됩니다. 다른 값에서는 WHEN OTHERS 뒤의 코드 블록이 실행됩니다.

CASE … ENDCASE를 사용하는 조건부 분기는 IF … ENDIF 구조로도 구현할 수 있습니다. 오른쪽에는 예제가 나와 있습니다.

힌트

코드 가독성을 높이기 위해 특수 케이스를 처리할 때는 CASE … ENDCASE를 사용해야 합니다.

사용해 보기: 조건부 분기

  1. 이 과정의 첫 번째 연습문제와 마찬가지로 인터페이스 IF_OO_ADT_CLASSRUN을 구현하는 신규 전역 클래스를 생성합니다.
  2. 다음 코드 스니핏을 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. CTRL + F3 을 눌러 클래스를 활성화하고 F9 를 눌러 콘솔 앱으로 실행합니다.
  4. 콘솔 출력을 분석합니다. 소스 코드를 사용하여 개념에 익숙해지십시오. 상수 c_number의 다른 선언의 주석 처리를 해제하여 다른 값을 표시하고, 어떤 코드 분기가 실행되는지 확인합니다.

예외 처리

예외

ABAP에서 예외는 ABAP 프로그램 실행 중 발생한 오류 상황입니다. 오류 상황을 감지하는 코드에서 예외가 발생합니다.

예외를 발생시키는 사람에 따라 시스템 예외와 어플리케이션 예외를 구분합니다.

예외를 추가로 측정하지 않으면 런타임 오류가 발생합니다. 런타임 오류가 발생하면 프로그램이 종료되고 오류 내역에 기본적으로 기록됩니다.

해당 예외를 캐치할 수 있는 경우 런타임 오류를 방지할 수 있습니다. TRY … CATCH … ENDTRY 문을 사용하여 프로그램에서 캐치 가능 예외를 처리할 수 있습니다.

모든 어플리케이션 예외와 많은 시스템 예외를 캐치할 수 있습니다. 이 과정의 후반부에서 어플리케이션 예외를 발생시키는 방법을 학습합니다. 이 시점에서는 캐치 가능한 시스템 예외의 처리에 대해 중점적으로 살펴보겠습니다.

다음 동영상에서는 런타임 오류의 몇 가지 예를 보여줍니다.

예외 처리

캐치 가능한 예외로 인해 프로그램이 종료되지 않도록 하려면 TRY 문과 ENDTRY 문을 사용하여 예외가 발생한 코드를 둘러싸야 합니다. 이렇게 하면 코드가 TRY … ENDTRY 구조의 TRY 블록에 포함됩니다.

ENDTRY 문 앞에 처리하려는 예외의 ID 뒤에 CATCH 문을 추가해야 합니다. CATCH 문을 여러 개 추가하여 여러 가지 예외를 처리할 수도 있습니다. 이 예외를 처리하려면 각 CATCH 문 뒤에 코드가 와야 합니다. 이 코드를 CATCH 블록이라고 합니다.

프로그램 실행이 TRY 문에 도달하면 TRY 블록의 코드로 계속됩니다. 그러면 다음 세 가지 상황이 발생할 수 있습니다.

  1. TRY 블록 중에 예외가 발생하지 않으면 CATCH 블록은 무시됩니다. ENDTRY 문 다음에 실행이 계속됩니다.
  2. 일치하는 CATCH가 있는 TRY 블록 중에 예외가 발생하면 TRY 블록의 실행이 종료되고 이 예외에 대한 CATCH 블록이 실행됩니다. 그런 다음 ENDTRY 문 다음에 계속 실행됩니다.
  3. 일치하는 CATCH가 없는 TRY 블록 중에 예외가 발생하면 프로그램이 런타임 오류로 인해 종료됩니다.

예외에 대해 학습했으므로 예외를 처리하는 방법을 살펴보겠습니다.

사용해 보기: 예외 처리

  1. 이 과정의 첫 번째 연습문제와 마찬가지로 인터페이스 IF_OO_ADT_CLASSRUN을 구현하는 신규 전역 클래스를 생성합니다.
  2. 다음 코드 스니핏을 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. CTRL + F3 을 눌러 클래스를 활성화하고 F9 를 눌러 콘솔 앱으로 실행합니다.
  4. 콘솔 출력을 분석합니다. 소스 코드를 사용하여 개념을 숙지하십시오.
    • 예외 처리를 주석 처리하여 시스템에서 런타임 오류가 발생하도록 합니다.
    • 예외가 발생하지 않도록 c_number, c_text, c_index, c_charin 상수 값을 변경합니다.

반복

반복은 여러 번 실행되는 코드 블록을 정의하는 제어 구조입니다.

가장 단순한 형태의 반복은 DO와 ENDDO 문의 쌍으로 둘러싸인 코드 블록으로 구성됩니다. 추가 조치가 없으면 다음 가능성 중 하나로 피해야 하는 무한 루프가 설정됩니다.

지정된 반복 횟수

DO 문을 정수 표현식과 키워드 TIMES로 확장하면 코드 블록을 반복할 빈도를 명시적으로 지정할 수 있습니다. 정수 표현식은 숫자 리터럴만큼 단순할 수 있지만 산술 계산도 선택 사항입니다. 표현식 값이 0이면 DO와 ENDDO 사이의 코드 블록이 전혀 실행되지 않고 ENDDO 뒤의 코드로 즉시 계속됩니다.

논리 조건에 따라 중단

EXIT 문을 사용하여 언제든지 반복을 중단할 수 있습니다. 그런 다음 ENDDO 뒤에 코드를 사용하여 프로그램이 계속됩니다. 반복 EXIT 이외의 경우에는 다른 효과가 있습니다. 여기에서 현재 처리 블록(예: 현재 메소드)의 처리가 종료됩니다.

일반적으로 EXIT는 IF 및 ENDIF 로 둘러싸여 있어 중단 조건에 따라 반복을 종료합니다. 중단 조건이 참이 아니면 이러한 반복이 무한 루프로 바뀔 수 있습니다.

물론 두 기법을 결합할 수 있습니다. 즉, 반복 횟수를 명시적으로 지정한 다음 EXIT 로 반복을 종료할 수 있습니다. 따라서 반복 횟수는 런타임 시 도달하지 못할 수 있는 최대 수가 됩니다.

내부 테이블(Internal Table) 기반

세 번째 반복 유형은 내부 테이블(Internal Table)의 행을 연속적으로 읽는 데 사용되는 LOOP … ENDLOOP 구조입니다. 여기서 반복 횟수는 내부 테이블의 행 수에 따라 결정됩니다.

DO와 ENDDO 사이의 코드 블록에서 ABAP 기본 제공 데이터 오브젝트 sy-index에 대한 읽기 액세스를 구현할 수 있습니다. 이 정수 변수는 반복 카운터 역할을 합니다. 즉, ABAP 런타임이 새로운 반복을 시작할 때마다 하나씩 증가시킵니다.

다른 프로그래밍 언어에서 사용될 수 있는 것과 달리, sy-index는 첫 번째 반복 중에 값 1로 시작합니다.

ABAP 기본 제공 변수 sy-tabix는 LOOP를 사용한 반복의 유사한 목적을 충족할 수 있습니다. 그러나 엄밀히 말하면 sy-tabix는 실제로 카운터가 아니지만 현재 반복에서 처리되는 테이블 행의 위치를 식별합니다. 나중에 내부 테이블의 일부 행이 LOOP … ENDLOOP 구조에서 처리되지 않을 때 차이를 볼 수 있습니다.

사용해 보기: 반복

  1. 이 과정의 첫 번째 연습문제와 마찬가지로 인터페이스 IF_OO_ADT_CLASSRUN을 구현하는 신규 전역 클래스를 생성합니다.
  2. 다음 코드 스니핏을 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. CTRL + F3 을 눌러 클래스를 활성화하고 F9 를 눌러 콘솔 앱으로 실행합니다.
  4. 콘솔 출력을 분석합니다. 소스 코드를 사용하여 개념에 익숙해지십시오. 상수 c_number의 다른 선언의 주석 처리를 해제하여 서로 다른 값이 결과에 어떤 영향을 미치는지 확인합니다.