14. Messages
14.1. 00消息ID中的通用消息
00消息ID中的001消息本身未設置任何消息串,這條消息可以傳遞8個參數,在用於拼接消息時很有用
MESSAGE e001(00) WITH 'No local currecny maintained for company:' p_bukrs.
14.2. 消息常量
直接顯示消息常量,不引用消息ID與消息號
MESSAGE 'aaaa' TYPE 'S'.
14.3. 靜態指定
MESSAGE <t><nnn>(<id>) [with<f1>... <f4>][raising <exc>].
MESSAGE s002(00).
14.4. 動態指定
MESSAGE ID <id> TYPE <t> NUMBER <n> [with<f1>...<f4>] [raising <exc>].
DATA: t(1) VALUE 'S',
id(2) VALUE '00',
num(3) VALUE '002'.
MESSAGE ID id TYPE t NUMBER num.
14.5. 消息拼接MESSAGE …INTO
DATA mtext TYPE string.
CALL FUNCTION ... EXCEPTIONS error_message = 4.
IF sy-subrc = 4.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
INTO msgtext
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
14.6. 修改消息顯示性為…DISPLAY LIKE…
此種方式不會影響到消息本身的處理性為,只是改變了消息的顯示圖標類型,如下面只是改變了S類型消息在狀態欄中以錯誤圖標來顯示(本來是綠色狀態圖標):
MESSAGE msg TYPE 'S' DISPLAY LIKE 'E'.
:消息以異常形式拋出">14.7. RAISING <exc>:消息以異常形式拋出
MESSAGE ID 'SABAPDEMOS' TYPE MESSAGE_TYPE NUMBER '777'
WITH MESSAGE_TYPE MESSAGE_PLACE MESSAGE_EVENT
RAISING MESS.
當使用該選項后,並且如果在調用的地方(CALL FUNCTION或者是 CALL METHOD的地方)使用了EXCEPTION選項來捕獲RAISING拋出的異常,則不再以MESSAGE的原有形式來顯示消息,而是被主調捕獲后進一步處理或者是程序Dump(A、E、W、I、S類型都能被捕獲到,但X類型的Message不會走到被主調者捕獲這一步,因為在被調程序中就宕掉了);反過來,當主調者未使用EXCEPTION選項(或者使用了但未捕獲到所拋出的異常),則RAISING選項會被忽略,MESSAGE語句會按照無RAISING選項時那樣運行(彈框還是在狀態欄中顯示、以及程序是否終止等性為、還是轉換為error_message拋出)
如果加了選項RAISING時:MESSAGE... RAISING <exc>,此時的Message 的處理方式與是否顯示,就要依賴於主調者在調用時,是否加上了exception <exc>選項:
1、如果調用時沒有帶exception <exc>選項,此時Message語包中的RAISING <exc>選項拋出的異常將會被忽略,Message語句會當作正常消息來處理
2、 如果調用時加上了exception <exc>選項對exc 異常進行了捕獲,則不會再顯示消息(但如果即使加上了exception選項,但沒有捕獲到exc異常,則此時會忽略RAISING選項),並設置sy-subrc。只要異常被捕獲,相關消息內容將會入存入到SY-MSGID,SY-MSGTY, SY-MSGNO, and SY-MSGV1 to SY-MSGV4有關系統變量中。
下面程序中,第一次調用時中會彈出消息框(因為沒有使用EXCEPTIONS選項捕獲),而第二次不會彈出消息框,也不會在狀態欄中顯示,而是被后繼程序捕獲后輸出:
CLASS c1 DEFINITION.
PUBLIC SECTION.
CLASS-METHODS m1 EXCEPTIONS exc1.
ENDCLASS.
CLASS c1 IMPLEMENTATION.
METHOD m1.
MESSAGE 'Message in a Method' TYPE 'I' RAISING exc1.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
c1=>m1( )."第一次調用
c1=>m1( EXCEPTIONS exc1 = 4 )."第二次調用
IF sy-subrc = 4.
write: / '被捕獲'.
ENDIF.
14.8. CALL FUNCTION…EXCEPTIONS
CALL FUNCTION func [EXCEPTIONS
[exc1= n1 exc2= n2]
[others= n_others] ]
[ERROR_MESSAGE = n_error].
exc1,exc2...與OTHERS異常只能捕獲到MESSAGE...RAISING選項或RAISE語句拋出的異常,而error_message是無法捕獲MESSAGE...RAISING與RAISE拋出的異常的
MESSAGE中的RAISING <exc1...exci>拋出異常時,如果在Call Function的Exception列表中有exc1...exci或others異常,則異常會優先被exc1...exci或others捕獲到;否則RAISING選項將直接被忽略掉,MESSAGE會被error_message所捕獲(在使用error_message捕獲的前提下)
CALL FUNCTION 'ZJZJ_FUNC1'
EXCEPTIONS
error_message = 5
"被e捕獲,如果注釋掉下面E類型異常捕獲列表,則會被error_message捕獲
e = 4
d = 6.
14.8.1. error_message = n_error捕獲消息
可以在Message語句沒有使用RAISING選項的情況下(或使用exc1...exci或others但未捕獲到),在主調程序中的CALL FUNCTION ...Exception參數列表中使用隱式異常error_message選項來捕獲Message,但error_message是否能捕獲到Message(實為是否設置sy-subrc = n_error),與消息類型有關:
1、對於W、I、S類型的消息,將不顯示消息(本來是要顯示的),也不會去設置 sy-subrc = n_error,但此時還是會將消息的相關信息存儲到SY-MSGID, SYMSGTY,SY-MSGNO, and SY-MSGV1 to SY-MSGV4這些系統變量中
2、對於A、E類型消息,也將不顯示提示消息,但會拋出ERROR_MESSAGE異常,即這兩類型的消息會自動被轉換為error_message異常拋出,並終最被CALL FUNCTION 中Exception異常列表中的error_message異常所捕獲,並設置sy-subrc = n_error。此時還會將消息的相關信息存儲到SY-MSGID, SYMSGTY,SY-MSGNO, and SY-MSGV1 to SY-MSGV4這些系統變量中
此時,對於A類型消息而言,ROLLBACK WORK語句將會隱式執行
3、對於X類型消息將會拋出runtime error,並且程序會dump
14.9. 各種消息的顯示及處理
消息類型 |
非屏幕PAI事件 PBO、 AT SELECTION-SCREEN OUTPUT、INITIALIZATION、START-OF-SELECTION、 GET、 END-OF-SELECTION、 TOP-OF-PAGE、 END-OF-PAGE |
對話/選擇屏幕 PAI、 AT SELECTION-SCREEN [ON] |
List列表事件 AT LINE-SELECTION、 AT USER-COMMAND、 AT PF<nn>、 |
|||
顯示 顯示在對話框中還是狀態欄中 |
處理 是終止程序還是繼續 |
顯示 |
處理 |
顯示 |
處理 |
|
X |
不顯示信息 |
觸發運行時錯誤並伴隨着dump |
不顯示信息 |
觸發運行時錯誤並伴隨着dump |
不顯示信息 |
觸發運行時錯誤並伴隨着dump |
A |
Dialogbox以對話框形式顯示 |
程序終止 |
Dialogbox以對話框形式顯示 |
程序終止 |
Dialogbox以對話框形式顯示 |
程序終止 |
PBO:與A相同,否則顯示在狀態欄中 |
程序終止 |
在狀態欄中顯示 |
PAI處理結束,並且控制權返回到當前對話/選擇屏幕繼續輸入 |
在狀態欄中顯示 |
||
W |
PBO:與S相同,否則顯示在狀態欄中 |
程序終止 |
在狀態欄中顯示 |
PAI處理結束,並且控制權返回到當前對話/選擇屏幕可繼續輸入,但可按回車鍵繼來忽略警告繼續運行后面程序而不必輸入 |
在狀態欄中顯示 |
事件塊處理終止,返回上一級別的List |
I |
PBO:與S相同,否則以對話框的形式顯示 |
程序會繼續向下執行 |
Dialog box對話框中顯示 |
程序會繼續向下執行 |
Dialog box對話框中顯示 |
程序會繼續向下執行 |
S |
消息會顯示在下一屏幕的狀態欄中,如果沒有下一屏幕,則顯示在當前屏幕的狀態欄中 |
程序會繼續向下執行 |
消息會顯示在下一屏幕的狀態欄中,如果沒有下一屏幕,則顯示在當前屏幕的狀態欄中 |
程序會繼續向下執行 |
消息會顯示在下一屏幕的狀態欄中,如果沒有下一屏幕,則顯示在當前屏幕的狀態欄中 |
程序會繼續向下執行 |
14.10. 異常處理
14.10.1. RAISE [EXCEPTION]…觸發異常
兩種方式觸發異常:
l RAISE <except>. 只在函數中使用
一旦主調程序捕獲了異常,以上兩種觸發異常的方式都會返回到主調程序,並且不會返回值(Function Module參數輸出)。MESSAGE ..... RAISING語句也不會再顯示消息,而是將相關的信息填充到SY-MSGID, SY-MSGTY,SY-MSGNO, and SY-MSGV1 to SY-MSGV4這些系統變量中(即使是I,S,W三種消息類型也會設置這些系統變量)
14.10.1.1.觸發類異常
RAISE [RESUMABLE] EXCEPTION { { TYPE cx_class [EXPORTING p1 = a1 p2 = a2 ...]} | oref }.
cx_class為異常Class,EXPORTING為構造此異常類的構造參數,oref可以是已存在的異常Class引用。
RAISE EXCEPTION語句一般用來拋出基於Class的異常類class-based exceptions,而RAISE一般是直接用來拋出 non-class-based exceptions(在函數中使用)
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.
ENDTRY.
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.
14.10.1.2.RESUMABLE選項
表示可恢復的異常,可以在CATCH塊里使用RESUME語句直接跳到拋出異常語句后面繼續執行,RESUME后面語句不再被執,CLEANUP塊也不會被執行。該選項只能用於BEFORE UNWIND類型的CATCH塊中:
DATA oref TYPE REF TO cx_root.
DATA text TYPE string.
DATA i TYPE i.
TRY .
RAISE RESUMABLE EXCEPTION TYPE cx_demo_constructor
EXPORTING
my_text = sy-repid.
i = i + 1.
WRITE: / i.
CATCH BEFORE UNWIND cx_demo_constructor INTO oref .
text = oref->get_text( ).
IF i < 1.
RESUME.
ENDIF.
WRITE:/ '--'.
ENDTRY.
結果只輸出 1
14.10.2. 捕獲異常
14.10.2.1.類異常捕獲TRY…CATCH
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.
14.10.2.2.老式方式捕獲runtime errors(運行時異常)
CATCH SYSTEM-EXCEPTIONS [exc1 = n1 exc2 = n2 ...][OTHERS = n_others].
…
ENDCATCH.
DATA: result TYPE i.
CATCH SYSTEM-EXCEPTIONS arithmetic_errors = 5.
result = 1 / 0.
ENDCATCH.
IF sy-subrc = 5.
WRITE / 'Division by zero!'.
ENDIF.
14.10.3. 向上拋出異常
如果Form中出現了運行時錯誤,但Form簽名又沒有使用RAISING向上拋,則程序會直接掛掉,所以最好是向上拋
FORM subform RAISING cx_static_check cx_dynamic_check.
...
ENDFORM.
Funcion函數不會主動向外拋出運行時錯誤,所以要先在Function手動CATCH,再手動向外拋,如果出現運行時錯誤不拋出,則Function與會直接宕掉
14.10.4. 類異常
l CX_STATIC_CHECK
l CX_DYNAMIC_CHECK
l CX_NO_CHECK
CX_NO_CHECK類似於Java中的Error,CX_DYNAMIC_CHECK類似於Java中的RuntimeException,CX_STATIC_CHECK類似於Java檢測性異常Exception
自己定義的異常一般繼承CX_STATIC_CHECK、CX_DYNAMIC_CHECK,但CX_NO_CHECK也可以創建,不像Java
CX_STATIC_CHECK是一個抽象類。在程序中使用RAISE EXCEPTION 手動拋出這類異常時,方法或過程接口上一定要顯示的通過RAISING 來向上層拋出異常、或者直接在方法或過程中進行處理也可以,否則靜態編譯時就會出現警告。
CX_NO_CHECK類型的異常一般表示系統資源不足引起的,不能在方法或過程接口后面拋出CX_NO_CHECK類型的異常,它會被隱含的拋出與傳遞。系統中已有預定義這類異常。
如果程序邏輯能夠排除可能性的潛在性錯,相應的異常就可能不用處理或繼續拋出,此類情況下可以使用CX_DYNAMIC_CHECK類型的異常,這與Java中的運行時異常相似,一旦發生也該類異常,表示問題出現在程序的本身設計上,程序設計不嚴謹(如沒有判斷空指針問題)。ABAP大多數的系統預定義的異類都是屬於該類型異常,這就意味着不需要處理或拋出ABAP語句可能出現的每一種異常,但一旦發生了該類異常,則表示程序的出現了問題,程序執行的結果將不會在正確。
自定義的全局異常類名以ZCX_ 作為前綴
如果是通過Class Builder創建的全局異常類時,由於構造器是默認創建好的(異常相關參數已經固定下來了),不能傳遞自定義參數,所以異常文本ID只能通過TEXTID傳遞(參考觸發類異常),但局部異常類沒有這個限制。