La structure TRY...CATCH...ENDTRY est le concept moderne de gestion des erreurs en ABAP. Elle permet d’intercepter les erreurs d’exécution (exceptions) et d’y réagir de manière contrôlée, au lieu que le programme plante.
Concept de base
- Exception : Un objet d’erreur qui est déclenché en cas de problème
- Bloc TRY : Code susceptible de déclencher des exceptions
- Bloc CATCH : Code qui traite l’exception
- Bloc CLEANUP : Code toujours exécuté (travaux de nettoyage)
Syntaxe
Structure de base
TRY. " Code susceptible de déclencher des exceptions CATCH <classe_exception> [INTO <reference>]. " Traitement de l'erreur [CATCH <autre_exception> INTO <reference>.] " Autre traitement d'erreur [CLEANUP. " Travaux de nettoyage (optionnel)]ENDTRY.Déclencher une exception
RAISE EXCEPTION TYPE <classe_exception> [EXPORTING <parametre> = <valeur>].Champs système
Après un CATCH :
- La référence d’exception contient les détails de l’erreur
sy-subrcn’est pas défini (est pour la gestion d’erreur classique)
Exemples
1. TRY-CATCH simple
DATA: lv_result TYPE i.
TRY. lv_result = 10 / 0. " Division par zéro CATCH cx_sy_zerodivide. WRITE: / 'Erreur : Division par zéro !'.ENDTRY.
WRITE: / 'Le programme continue.'.2. Lire les détails de l’exception
DATA: lx_error TYPE REF TO cx_sy_zerodivide.
TRY. DATA(lv_result) = 10 / 0. CATCH cx_sy_zerodivide INTO lx_error. " Lire le message d'erreur DATA(lv_message) = lx_error->get_text( ). WRITE: / 'Erreur :', lv_message.
" Informations supplémentaires DATA(lv_longtext) = lx_error->get_longtext( ).ENDTRY.3. Traiter plusieurs types d’exceptions
DATA: lv_number TYPE i, lv_text TYPE string VALUE 'ABC'.
TRY. lv_number = lv_text. " Erreur de conversion CATCH cx_sy_conversion_no_number INTO DATA(lx_conv). WRITE: / 'Erreur de conversion :', lx_conv->get_text( ). CATCH cx_sy_zerodivide INTO DATA(lx_div). WRITE: / 'Division par zéro :', lx_div->get_text( ). CATCH cx_root INTO DATA(lx_any). " Intercepte toutes les autres exceptions WRITE: / 'Erreur générale :', lx_any->get_text( ).ENDTRY.4. Hiérarchie d’exceptions (cx_root)
Toutes les exceptions ABAP héritent de cx_root. La hiérarchie :
cx_root (classe de base)├── cx_static_check (doit être déclaré ou intercepté)├── cx_dynamic_check (devrait être intercepté)└── cx_no_check (erreurs graves, généralement non interceptables)TRY. " Du code quelconque CATCH cx_static_check INTO DATA(lx_static). " Intercepte toutes les exceptions vérifiables statiquement CATCH cx_dynamic_check INTO DATA(lx_dynamic). " Intercepte toutes les exceptions vérifiables dynamiquement CATCH cx_root INTO DATA(lx_all). " Intercepte vraiment toutes les exceptionsENDTRY.5. Déclencher et déclarer une exception dans une méthode
CLASS lcl_validator DEFINITION. PUBLIC SECTION. METHODS: validate_age IMPORTING iv_age TYPE i RAISING cx_parameter_invalid.ENDCLASS.
CLASS lcl_validator IMPLEMENTATION. METHOD validate_age. IF iv_age < 0 OR iv_age > 150. RAISE EXCEPTION TYPE cx_parameter_invalid EXPORTING parameter = 'AGE'. ENDIF. ENDMETHOD.ENDCLASS.
" UtilisationDATA: lo_validator TYPE REF TO lcl_validator.lo_validator = NEW #( ).
TRY. lo_validator->validate_age( -5 ). WRITE: / 'L\'âge est valide.'. CATCH cx_parameter_invalid INTO DATA(lx_invalid). WRITE: / 'Paramètre invalide :', lx_invalid->get_text( ).ENDTRY.6. Créer sa propre classe d’exception
" Définir une classe d'exceptionCLASS lcx_customer_not_found DEFINITION INHERITING FROM cx_static_check. PUBLIC SECTION. INTERFACES: if_t100_message. METHODS: constructor IMPORTING iv_customer_id TYPE i !previous TYPE REF TO cx_root OPTIONAL, get_customer_id RETURNING VALUE(rv_id) TYPE i. DATA: mv_customer_id TYPE i READ-ONLY.ENDCLASS.
CLASS lcx_customer_not_found IMPLEMENTATION. METHOD constructor. super->constructor( previous = previous ). mv_customer_id = iv_customer_id. ENDMETHOD.
METHOD get_customer_id. rv_id = mv_customer_id. ENDMETHOD.ENDCLASS.
" UtilisationCLASS lcl_customer_service DEFINITION. PUBLIC SECTION. METHODS: get_customer IMPORTING iv_id TYPE i RETURNING VALUE(rs_customer) TYPE zcustomer RAISING lcx_customer_not_found.ENDCLASS.
CLASS lcl_customer_service IMPLEMENTATION. METHOD get_customer. SELECT SINGLE * FROM zcustomer WHERE id = @iv_id INTO @rs_customer.
IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_customer_not_found EXPORTING iv_customer_id = iv_id. ENDIF. ENDMETHOD.ENDCLASS.
" AppelDATA: lo_service TYPE REF TO lcl_customer_service.lo_service = NEW #( ).
TRY. DATA(ls_customer) = lo_service->get_customer( 12345 ). WRITE: / 'Client trouvé :', ls_customer-name. CATCH lcx_customer_not_found INTO DATA(lx_not_found). WRITE: / 'Client non trouvé. ID :', lx_not_found->get_customer_id( ).ENDTRY.7. CLEANUP pour travaux de nettoyage
Le bloc CLEANUP est exécuté lorsqu’une exception quitte le bloc TRY :
DATA: lo_file TYPE REF TO cl_file.
TRY. " Ouvrir un fichier lo_file = NEW #( 'data.txt' ). lo_file->open( ).
" Traitement (peut déclencher une exception) lo_file->read( ).
CATCH cx_file_error INTO DATA(lx_file). WRITE: / 'Erreur de fichier :', lx_file->get_text( ).
CLEANUP. " Est TOUJOURS exécuté, même en cas d'exception IF lo_file IS BOUND. lo_file->close( ). ENDIF.ENDTRY.8. Blocs TRY imbriqués
TRY. TRY. DATA(lv_result) = 10 / 0. CATCH cx_sy_zerodivide. WRITE: / 'Erreur interne : Division par zéro'. " Propager l'exception RAISE EXCEPTION TYPE cx_sy_arithmetic_error. ENDTRY. CATCH cx_sy_arithmetic_error INTO DATA(lx_math). WRITE: / 'Erreur externe :', lx_math->get_text( ).ENDTRY.9. RETRY - Répétition après erreur
Avec RETRY, le bloc TRY peut être répété :
DATA: lv_attempts TYPE i VALUE 0, lv_success TYPE abap_bool VALUE abap_false.
TRY. lv_attempts = lv_attempts + 1. WRITE: / 'Tentative :', lv_attempts.
" Erreur simulée dans les 2 premières tentatives IF lv_attempts < 3. RAISE EXCEPTION TYPE cx_sy_dyn_call_error. ENDIF.
lv_success = abap_true. WRITE: / 'Réussi !'.
CATCH cx_sy_dyn_call_error. IF lv_attempts < 3. WRITE: / 'Erreur - nouvelle tentative...'. RETRY. " Retour au TRY ELSE. WRITE: / 'Nombre maximum de tentatives atteint.'. ENDIF.ENDTRY.10. Exception avec RESUMABLE (Reprise possible)
CLASS lcx_warning DEFINITION INHERITING FROM cx_static_check. PUBLIC SECTION. METHODS constructor.ENDCLASS.
CLASS lcx_warning IMPLEMENTATION. METHOD constructor. super->constructor( ). ENDMETHOD.ENDCLASS.
CLASS lcl_processor DEFINITION. PUBLIC SECTION. METHODS: process RAISING RESUMABLE(lcx_warning).ENDCLASS.
CLASS lcl_processor IMPLEMENTATION. METHOD process. WRITE: / 'Le traitement démarre...'. RAISE RESUMABLE EXCEPTION TYPE lcx_warning. WRITE: / 'Le traitement a repris !'. ENDMETHOD.ENDCLASS.
" UtilisationDATA: lo_proc TYPE REF TO lcl_processor.lo_proc = NEW #( ).
TRY. lo_proc->process( ). CATCH BEFORE UNWIND lcx_warning. WRITE: / 'Avertissement reçu - continuer avec RESUME'. RESUME. " Continue l'exécution après RAISEENDTRY.Classes d’exceptions standard
| Classe | Description |
|---|---|
cx_sy_zerodivide | Division par zéro |
cx_sy_arithmetic_error | Erreurs arithmétiques |
cx_sy_conversion_no_number | Conversion chaîne vers nombre |
cx_sy_range_out_of_bounds | Index de tableau hors limites |
cx_sy_itab_line_not_found | Ligne de table non trouvée |
cx_sy_ref_is_initial | Déréférencement de NULL |
cx_sy_move_cast_error | Downcast invalide |
cx_sy_dyn_call_error | Erreur d’appel dynamique |
Gestion des exceptions dans les méthodes
CLASS lcl_example DEFINITION. PUBLIC SECTION. " L'exception doit être déclarée (cx_static_check) METHODS: method_with_exception RAISING cx_parameter_invalid.
" L'exception ne doit PAS être déclarée (cx_dynamic_check) METHODS: method_with_runtime_error.
" Propager l'exception METHODS: wrapper_method RAISING cx_parameter_invalid.ENDCLASS.
CLASS lcl_example IMPLEMENTATION. METHOD method_with_exception. RAISE EXCEPTION TYPE cx_parameter_invalid. ENDMETHOD.
METHOD method_with_runtime_error. DATA(lv_x) = 1 / 0. " cx_sy_zerodivide (dynamic_check) ENDMETHOD.
METHOD wrapper_method. " L'exception est propagée method_with_exception( ). ENDMETHOD.ENDCLASS.TRY-CATCH vs. Gestion d’erreur classique
| Aspect | TRY-CATCH | sy-subrc |
|---|---|---|
| Type | Orienté objet | Procédural |
| Information | Exception détaillée | Code de retour uniquement |
| Propagation | Automatique vers le haut | Vérification manuelle |
| Recommandation | Moderne, préféré | Legacy, pour Open SQL |
Remarques importantes / Bonnes pratiques
- N’interceptez que les exceptions que vous pouvez traiter de manière sensée.
- Utilisez des classes d’exception spécifiques, pas seulement
cx_root. - Créez vos propres classes d’exception pour les erreurs spécifiques au domaine.
- Utilisez
INTOpour lire les détails de l’erreur. - Le bloc
CLEANUPest important pour la libération de ressources. - Déclarez les exceptions dans les signatures de méthodes avec
RAISING. cx_static_checknécessite un traitement ou une déclaration explicite.- Journalisez les exceptions pour le débogage et la surveillance.
- Combinez avec
CLASSetINTERFACEpour une architecture propre. - Après les opérations de base de données avec
SELECT, vérifiez toujourssy-subrc.