異常處理
基於類的異常是從6.10版本開始,它們是以異常類實例方式來實現。異常類是系統預先定義好的全局類或者是由用戶自定義的局部或全局的類。
在sap6.10版本里,exception classes已經取代了catchable runtime errors
基於類的異常exception classes 捕獲
DATA myref TYPE REF TO cx_sy_arithmetic_error.
DATA err_text TYPE string.
DATA result TYPE i.
TRY.
result = 1 / 0.
CATCH cx_sy_arithmetic_error INTO myref.
err_text = myref->get_text( ).
ENDTRY.
這個寫法與java是相似的
使用老式方式捕獲catchable runtime errors
catchable runtime errors
CATCH SYSTEM-EXCEPTIONS [exc1 = n1 exc2 = n2 ...]
[OTHERS = n_others].
[statement_block]
ENDCATCH.
OTHERS接收所有前面異常列表 n1 n2 …未捕獲到的異常。
DATA: result TYPE i.
CATCH SYSTEM-EXCEPTIONS arithmetic_errors = 5.
result = 1 / 0.
ENDCATCH.
IF sy-subrc = 5.
WRITE / 'Division by zero!'.
ENDIF.
現一般不用這種方式了,而是這樣:
DATA result TYPE p DECIMALS 2.
DATA oref TYPE REF TO cx_root.
DATA text TYPE string.
DATA i TYPE i.
TRY .
i = 1 / 0.
CATCH cx_root INTO oref.
text = oref->get_text( ).
WRITE: '---' , text.
RAISE EXCEPTION oref.”注:如果有此句,則不能放在Function中,否則報:Old and class-based exceptions must not be used the same time
ENDTRY.
向上拋出異常
如果Form中出現了運行時錯誤,但Form簽名又沒有使用RAISING向上拋,則程序會直接掛掉,所以最好是向上拋
FORM subform RAISING cx_static_check cx_dynamic_check.
...
ENDFORM.
Funcion函數不會主動向外拋出運行時錯誤,所以要先在Function手動CATCH,再手動向外拋,如果出現運行時錯誤不拋出,則Function與會直接宕掉:
手動觸發異常(類異常)
RAISE EXCEPTION { {TYPE cx_class [EXPORTING p1 = a1 p2 = a2 ...]}
| oref }.
EXPORTING選項表示的是異常類構造函數的參數。
DATA: exc TYPE REF TO cx_sy_dynamic_osql_semantics,
text TYPE string.
TRY.
RAISE EXCEPTION TYPE cx_sy_dynamic_osql_semantics
EXPORTING textid = cx_sy_dynamic_osql_semantics=>unknown_table_name token = 'Test'.
CATCH cx_sy_dynamic_osql_semantics INTO exc.
text = exc->get_text( ).
MESSAGE text TYPE 'I'.
ENDTRY.
6.1版本以后,TRY…ENDTRY結構:
TRY.
[try_block]
CATCH cx_class1 cx_class2 ... [INTO oref].
[catch_block]
...
[CLEANUP [INTO oref].
[cleanup_block]]
ENDTRY.
CLEARUP是在所在的TRY CATCH發生了異常,但在本TRY CATCH中無法捕獲,異常再次向上遞交給上層TRY CATCH前被執行的,它不同於Java中的finally
PARAMETERS number TYPE i.
DATA result TYPE p DECIMALS 2.
DATA oref TYPE REF TO cx_root.
DATA text TYPE string.
START-OF-SELECTION.
TRY.
IF ABS( number ) > 100.
RAISE EXCEPTION TYPE cx_demo_abs_too_large.
ENDIF.
TRY.
result = 1 / number.
WRITE: / 'Result of division:', result.
result = SQRT( number ).
WRITE: / 'Result of square root:', result.
CATCH cx_sy_zerodivide INTO oref."輸出0時會在這里捕獲
text = oref->get_text( ).
CONCATENATE 'CATCH cx_sy_zerodivide : ' text INTO text.
CLEANUP."當內層TRY發生了異常,且沒有被捕獲到,拋到外層TRY前會被執行
CLEAR result.
WRITE: / 'cleanup'.
ENDTRY.
CATCH cx_sy_arithmetic_error INTO oref."輸入負數會在這里捕獲
text = oref->get_text( ).
CONCATENATE 'CATCH cx_sy_arithmetic_error : ' text INTO text.
CATCH cx_root INTO oref."輸入的數大於100時會在這里捕獲
text = oref->get_text( ).
CONCATENATE 'CATCH cx_root : ' text INTO text.
ENDTRY.
IF NOT text IS INITIAL.
WRITE / text.
ENDIF.
WRITE: / 'Final result:', result.
異常的觸發:
l 運行出錯時,系統會自動觸發預定好的異常類(類似於Java中的運行時異常,6.10前是觸發的預定好的錯誤)
l 可以使用RAISE EXCEPTION手動觸發異常(類似Java的throw)
l 對於局部的類的METHODS、過程FORM后加上RAISING 選項來聲明要拋出的異常,向上繼續拋出(類似Java的throws),全局的函數異常在Exceptions標簽里如下設置:
在代碼中手動直接拋出異常即可:
l 類的靜態構造函數不能拋出異常
l event handler定義時不能拋出異常
l 使用SUBMIT ... AND RETURN 或者CALL TRANSACTION調用程序時,不能將異常傳播給調用者,因為異常對象是與程序的內部會話綁定的
三類異常:
l CX_STATIC_CHECK
l CX_DYNAMIC_CHECK
l CX_NO_CHECK
具體的異常類繼承結構請查看SAP幫助,輸入“EXCEPTION”
類比:CX_NO_CHECK類似於Java中的Error,CX_DYNAMIC_CHECK類似於Java中的RuntimeException,CX_STATIC_CHECK類似於Java檢測性異常
CX_STATIC_CHECK是一個抽象類,一般自己定的異常都要求繼承於它。在程序中使用RAISE EXCEPTION 手動拋出這類異常時,方法或過程接口上一定要顯示的通過RAISING 來向上層拋出異常(或者直接在方法或過程中進行處理也可以),否則靜態編譯時就會出現警告。
CX_NO_CHECK類型的異常一般表示系統資源不足引起的,不能在方法或過程接口后面拋出CX_NO_CHECK類型的異常,它會被隱含的拋出與傳遞。系統中已有預定義這類異常。
如果程序邏輯能夠排除可能性的潛在性錯,相應的異常就可能不用處理或繼續拋出,此類情況下可以使用CX_DYNAMIC_CHECK類型的異常,這與Java中的運行時異常相似,一旦發生也該類異常,表示問題出現在程序的本身設計上,程序設計不嚴謹(如沒有判斷空指針問題)。ABAP大多數的系統預定義的異類都是屬於該類型異常,這就意味着不需要處理或拋出ABAP語句可能出現的每一種異常,但一旦發生了該類異常,則表示程序的邏輯出現了問題,程序執行的結果將不會在正確。
異常類可以被定義成全局的類或者是局部的異常類,全局異常類名稱以CX_, YCX_, ZCX_為前綴。系統里預定義好的全局異常類都是能CX_SY_為前綴來命名的。
如果是通過Class Builder創建的全局異常類時,由於構造器是默認創建好的,不能傳遞參數,所以異常文本ID只能通過TEXTID傳遞,但局部異常類沒有這個限制。
如果在拋出的異常類在構造的過程中(構造函數中)發生了異常,則會使用CX_SY_NO_HANDLER異常來代替原來的異常實例。
函數異常的定義、拋出、與處理
CALLFUNCTION時一定不能省略Exceptions選項(EXCEPTIONS表示函數接口需要拋出異常,如果函數里拋出了異常,但調用時接口上沒有加上該選項,則程序運行時會中斷),否則異常不能捕獲,運行時會出錯。其實Exception先項就相當於TRY ... CATCH...
Exception Handling
關於異常更多詳情,請參考SAP 幫助Exception Handling