Estas sentencias se utilizan para señalar activamente una situación de excepción (Exception) en el flujo del programa. Lo haces típicamente cuando:
- Ocurre un error que la unidad de programa actual (método, módulo de función, form routine) no puede resolver por sí misma.
- Se alcanza un estado inesperado o inválido.
- Se viola una determinada regla de negocio.
Lanzar una excepción interrumpe el flujo normal del programa en ese punto y pasa el control a un bloque especial de manejo de errores (bloque CATCH para excepciones basadas en clase) o al llamador (que luego verifica sy-subrc para excepciones no basadas en clase). Esto permite un manejo estructurado de errores.
Hay dos tipos principales de excepciones y por tanto dos variantes de RAISE:
1. Excepciones Basadas en Clase (Moderno, ¡Preferido!)
Este es el método estándar en ABAP moderno y orientado a objetos. Las excepciones aquí son objetos de clases de excepción especiales (que heredan de CX_ROOT).
Sintaxis
" 1. Lanzar una nueva excepción de una clase:RAISE EXCEPTION TYPE <ClaseExcepcion> [EXPORTING p1 = v1 p2 = v2 ...] " Pasar parámetros al constructor [MESSAGE { <msg> " Mensaje desde objeto/interfaz | ID <id> TYPE <t> NUMBER <n> [WITH v1 v2 v3 v4] " Mensaje desde T100 | oref->if_t100_message } ] " Mensaje desde otro objeto [USING MESSAGE]. " Usar mensaje desde TEXTID
" 2. Relanzar un objeto de excepción ya existente (p.ej. en CATCH):RAISE EXCEPTION <objeto_excepcion>.Funcionamiento
- Se crea un objeto de la
<ClaseExcepcion>especificada. A través deEXPORTINGse pueden pasar valores al constructor de la clase para proporcionar detalles sobre el error (p.ej., el valor erróneo, un ID). - Opcionalmente, a través de la adición
MESSAGEse puede vincular un mensaje de la gestión de mensajes (SE91) u otro objeto con la excepción (muchas clases de excepción implementan para esto la interfazIF_T100_MESSAGE). - El flujo normal del programa se detiene.
- El sistema busca hacia arriba en la pila de llamadas un bloque
TRY...CATCHque pueda manejar esta clase de excepción (o una de sus superclases). - Si se encuentra un bloque
CATCH, se ejecuta su código. - Si no se encuentra ningún bloque
CATCHadecuado, esto lleva a un error en tiempo de ejecución (short dump).
Clases de Excepción: Se crean en SE24 y típicamente heredan de
CX_STATIC_CHECK: Errores que potencialmente podrían ser reconocidos en tiempo de desarrollo por la verificación de sintaxis (pero no tienen que serlo). Normalmente deberían manejarse.CX_DYNAMIC_CHECK: Errores que solo ocurren en tiempo de ejecución, pero que deberían ser esperados y manejados por el programa.CX_NO_CHECK: Errores graves e inesperados, donde el manejo no está necesariamente previsto (a menudo lleva a dump si no se captura explícitamente).- Manejo de errores: El llamador captura estas excepciones con
TRY. ... CATCH cx_... INTO DATA(lo_exc). ... ENDTRY.
2. Excepciones No Basadas en Clase (Obsoleto)
Este es el método más antiguo, que se usa principalmente en módulos de función y métodos más antiguos.
Contexto: Solo tiene sentido en procedimientos (módulos de función, métodos, FORMs) que declaran tales excepciones en la adición EXCEPTIONS de su interfaz.
Sintaxis
RAISE <nombre_excepcion>.Funcionamiento
- La ejecución del procedimiento se termina inmediatamente.
- El sistema establece el campo del sistema
sy-subrca un valor que está asignado a este<nombre_excepcion>en la adiciónEXCEPTIONSdel llamador (CALL FUNCTION ... EXCEPTIONS <nombre_excepcion> = valor ...). - El llamador debe verificar
sy-subrcdespués de la llamada para determinar si esta excepción ocurrió.
- Estado: Se considera obsoleto para nuevos desarrollos, especialmente en el contexto orientado a objetos. Solo debería usarse cuando módulos más antiguos lo requieran.
Ejemplos
1: Lanzar y Capturar Excepción Basada en Clase
" Clase de excepción propia (simplificada)CLASS zcx_division_by_zero DEFINITION INHERITING FROM cx_static_check.ENDCLASS.CLASS zcx_division_by_zero IMPLEMENTATION.ENDCLASS.
START-OF-SELECTION. DATA dividend TYPE i VALUE 10. DATA divisor TYPE i VALUE 0. DATA result TYPE f. DATA lo_error TYPE REF TO zcx_division_by_zero.
TRY. IF divisor = 0. " Lanza nuestra propia excepción RAISE EXCEPTION TYPE zcx_division_by_zero. ELSE. result = dividend / divisor. WRITE: / 'Resultado:', result. ENDIF.
CATCH zcx_division_by_zero INTO lo_error. MESSAGE 'Error: ¡División por cero!' TYPE 'E'. " Opcional: Acceder a atributos/métodos de lo_error ENDTRY.
WRITE / 'El programa continúa después del bloque TRY.'.2: Excepción Basada en Clase con Mensaje
" Suposición: Mensaje 010 en clase ZMSG: 'El material &1 no está activo.'" Suposición: ZCX_MATERIAL_INACTIVE implementa IF_T100_MESSAGEDATA lv_matnr TYPE matnr VALUE 'M-INACTIVE'.DATA lo_mat_error TYPE REF TO zcx_material_inactive.
TRY. " ... La verificación resulta que el material está inactivo ... RAISE EXCEPTION TYPE zcx_material_inactive MESSAGE ID 'ZMSG' TYPE 'E' NUMBER '010' WITH lv_matnr.
CATCH zcx_material_inactive INTO lo_mat_error. MESSAGE lo_mat_error->get_text( ) TYPE 'E'. " Obtener mensaje de la excepción ENDTRY.3: Excepción No Basada en Clase (Concepto en Módulo de Función)
FUNCTION Z_DO_SOMETHING.*"----------------------------------------------------------------------*"*"Interfaz local:*" IMPORTING*" VALUE(INPUT) TYPE I*" EXPORTING*" VALUE(OUTPUT) TYPE I*" EXCEPTIONS*" INPUT_IS_ZERO " Excepción declarada*"---------------------------------------------------------------------- IF input = 0. RAISE input_is_zero. " lanza la excepción -> sy-subrc se establece en el llamador ELSE. output = 100 / input. ENDIF.ENDFUNCTION.
" Programa que llama:DATA result TYPE i.CALL FUNCTION 'Z_DO_SOMETHING' EXPORTING input = 0 IMPORTING OUTPUT = result EXCEPTIONS input_is_zero = 1 " Mapea excepción a sy-subrc = 1 OTHERS = 2.
IF sy-subrc = 1. MESSAGE '¡La entrada para Z_DO_SOMETHING fue cero!' TYPE 'W'.ELSEIF sy-subrc = 0. WRITE: / 'Resultado:', result.ENDIF.Notas Importantes / Mejores Prácticas
- Usa excepciones basadas en clase (
RAISE EXCEPTION TYPE ...) para todos los nuevos desarrollos. - Define clases de excepción propias descriptivas para casos de error específicos de tu aplicación. Hereda de
CX_STATIC_CHECKoCX_DYNAMIC_CHECK. - Implementa la interfaz
IF_T100_MESSAGEen tus clases de excepción para vincularlas fácilmente con clases de mensajes (SE91). - Pasa información de contexto relevante a través de la adición
EXPORTINGal constructor de la clase de excepción. - Captura excepciones de forma selectiva con
TRY...CATCH...ENDTRYdonde puedan manejarse de forma significativa. Deja que las excepciones no manejables lleven conscientemente a un dump (especialmente las basadas enCX_NO_CHECK). - Evita
RAISE <nombre_excepcion>en código nuevo, a menos que sea para interactuar con módulos de función muy antiguos.