標題:Error|Exception handling in AnyLogic models
鏈接:https://www.theanylogicmodeler.com/post/error-exception-handling-in-anylogic-models
作者:Yash Mishra
本文為您分享了一篇來自 Yash Mishra 的特邀客座博文。文章簡要概述了如何管理 AnyLogic 仿真模型中的錯誤,展示了 Java 中可用的標準錯誤處理架構的示例,并以在GIS地圖中嘗試查找路線為例,說明了如何在 AnyLogic 中實際使用它。他還展示了如何在代碼中拋出自己的錯誤,以創建一個更強大的模型,當事情沒有按預期進行時模型會向您發出警告。
注意:這篇文章只是對錯誤處理的快速概述。
在建立仿真模型時,我們經常會遇到錯誤。有時在編譯模型時會出現編譯錯誤,有時在執行模型時會出現運行錯誤。當這些錯誤發生時,我們會查看控制臺中的錯誤詳細信息,并努力糾正它們。本文將重點介紹如何處理運行時錯誤。
技術說明:Errors 和 Exceptions 是 Java 中的兩個不同的類,在這篇文章中,為簡單起見,我們將交替使用錯誤和異常。
運行時的錯誤可能由于各種原因而發生,一旦發生模型執行將立即停止。有一些運行時的錯誤,如 OutOfMemoryError、VirtualMachineError 等,是不可恢復的。但仍有許多運行錯誤是可以處理的,例如dividingByZero、indexOutOfBounds 等,以及著名的 NullPointerException。有時我們希望與其在這些錯誤發生時模型直接運行失敗,不如在錯誤發生時捕獲它們,處理它們并控制接下來的步驟。
所有此類錯誤都可以通過稱為異常處理的強大機制來處理。在 Java 中,它是通過 try-and-catch 塊完成的。
try { //Do some actions that might cause an error, e.g. divide by zero } catch(Exception e) { //print cannot divide by zero }
將可能引發錯誤的代碼放在 try-and-catch 塊中,模型就能夠自行處理錯誤并避免模型執行突然停止。
Java 中的某些函數會強制您應用錯誤處理。嘗試輸入下面的代碼,看看您得到的編譯錯誤。看看您是否可以使用 try-catch 方法解決它 ;-)
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
Date myDate = dateFormatter.parse("2021-02-01");
一
讓我們深入了解這個概念,看看異常處理的實際應用。最近,我正在為一家電子商務公司建立一個模型,在運輸部門,有一個要求是找到交付訂單的最佳路線。交付訂單的首選方式是使用鐵路路線(如果有),如果沒有,則使用公路。
為了啟動模型,我使用空間標記(Space Markup)面板中可用的GIS地圖組件。
由于首選路線是鐵路,我們在GIS地圖組件的參數上將Road type選擇為“Rail“
為了確定最佳路線,我們需要獲取兩個位置之間的距離。在地圖上,我們可以使用GIS地圖組件提供的 getDistanceByRoute 功能計算起始地點和目標地點之間的距離并獲取路線。
map.getDistanceByRoute(latFrom, lonFrom, latTo, lonTo)
對于這樣一個簡單的樣例,可以創建一個按鈕控件,并在按鈕控件的單擊部分中應用上述功能來查找距離,使用紐約作為起始地址 (40.71, 74.00) ,華盛頓特區作為目的地 (38.90, 77.03)。
我們可以看到它根據鐵路路線返回鐵路距離。棒極了,不是嗎?
現在讓我們來看另一個例子,我們的起始點是巴爾的摩(Baltimore)郊區的某個地方(39.76,-77.51),目的地是多倫多(Toronto)附近的一個偏遠地區(43.95,-81.27)。
它向我展示了一條直線......這看起來可不像一條鐵路。事情有些不對......
當我仔細查看地圖屬性時,我發現如果鐵路線路不存在,我需要選擇“show error dialog”。
然而,如果選擇“show error dialog”,當不存在軌道路線時,它將產生錯誤,但這無法解決我的問題,因為當彈出錯誤對話框時,模型將立刻停止。但實際上我們想找到一條替代的公路路線......
因此,除了顯示錯誤對話框(Show error dialog)外,我還需要一些東西來處理GIS地圖組件在沒有可用鐵路路線時產生的錯誤。為了克服這個問題,我們將使用 try-and-catch 塊的錯誤處理方法。
因此,在我的按鈕控件單擊部分中,我編寫了以下代碼來處理錯誤并保護模型不會突然停止。
try {
message = "The Rail distance is: " +
format(map.getDistanceByRoute(39.76, -77.51, 43.95,
-81.27)/1000) + "KM";
} catch(Error | Exception e) {
message = "couldn't find the route by rail, will deliver by road";
}
P.S.代碼“Erro
r | Exception”僅表示“...捕獲錯誤或異常”。您可以添加想要捕獲的任意數量的未測試類類型,并簡單地用“|”分隔它們。
由于錯誤處理,我們可以保持模型運行,但如果沒有可用的鐵路路線,業務需要通過公路交付產品。出于所有實際目的,AnyLogic 中的GIS地圖組件可以生成鐵路或公路的路線,但不能同時使用兩者的路線。
因此,想到的第一個解決方案是再添加另一個GIS地圖組件來計算公路距離,如果第一個GIS地圖組件由于鐵路路線不可用而引發錯誤,我們將調用第二個GIS地圖組件......
AnyLogic 不允許在同一個智能體上添加兩個GIS地圖組件。
為了克服這個問題,AnyLogic 提供了一個 Route Provider 組件,該組件將使用GIS地圖組件來查找距離。
所以我們可以在同一個智能體上擁有兩個Route Provider 組件(這是允許的 )。一個Route Provider 尋找鐵路路線,另一個尋找公路路線。Route Provider 組件有一個 getRoute() 函數,該函數將GIS地圖組件以及起始和目標坐標作為輸入,并將路線作為輸出返回。
try { traceln("The distance by Rail is :" + routeProviderRail.getRoute(map, gisPointSource, gisPointDestination).length(LENGTH_UNIT_KILOMETER)); } catch(Error | Exception e) { traceln("The distance by Road is :" + routeProviderCar.getRoute(map, gisPointSource, gisPointDestination).length(LENGTH_UNIT_KILOMETER)); }
可以使用空間標記面板中的gisPoint 組件,而不是上面代碼中使用的位置坐標。將它們作為標記放置在地圖上,會自動從GIS地圖組件中獲取位置坐標。
一
?選項A:在一個智能體內創建錯誤
我們還可以使用 AnyLogic Utilities 類提供的error function 在運行時拋出錯誤。這將引發由 AnyLogic 引擎處理的錯誤。當遇到任何其他錯誤時,如果不在 try-catch 環境中處理,也會突然停止模型。
//generating 1 with 90% and 0 with 10% probability int x = binomial(0.9, 1); //if x is 0 produce an error if(x==0) { error("value of x is 0, which is invalid. Hence, error"); } else { traceln("Happy life - No errors!!!"); }
上面的代碼被放置在一個循環事件中——一旦 x 變為 0,模型就會產生錯誤并停止。而且,當您查看控制臺時,您將能夠看到 if 塊中的錯誤字符串。
?選項B:在Java類中創建錯誤
自然,Utilities 類在 Java 類中不可用,除非您在創建Java類的實例時將某個智能體作為參數傳遞,因為智能體可以訪問 Utilities 類。要在 Java 類中創建錯誤或異常,您不僅需要創建新的錯誤類,還需要“拋出”它。
if (fuelLevel < 0) { throw new RuntimeException("Fuellevel can never be negative"); }
有多種類型的錯誤和異常可用,例如 RuntimeException、ParseError 等
一
總之:能夠在仿真中處理和創建運行時錯誤是一項非常有用的技能。有些函數需要您處理它們可能拋出的錯誤,而對于其他函數,您可能想要捕獲它們,然后執行一些其他操作以讓您更深入地了解錯誤,甚至嘗試替代操作。