2017-04-12 78 views
0

我有一個Listjobs需要x個步驟(比如5)。每個步驟必須成功才能繼續,如果任何步驟失敗,則必須提出票證,並且必須放棄執行當前job並繼續執行下一個job從循環內調用的方法打破循環

這就是我目前的(它的工作原理就像一個魅力)。

for(Job aJob: jobs){ 
    // Step 1 
    try{ 
     Obj objRet1 = method1(); 
     // use objRet1; 
    } 
    catch(Exception e){ 
     raiseTicket(errMsg1,e); 
     break; 
    } 

    // Step 2 
    try{ 
    Obj objRet2 = method2(); 
    // use objRet2; 
    } 
    catch(Exception e){ 
     raiseTicket(errMsg2,e); 
     break; 
    } 

    // Step 3 
    try{ 
    Obj objRet3 = method3(); 
    // use objRet3; 
    } 
    catch(Exception e){ 
     raiseTicket(errMsg3,e); 
     break; 
    } 

    ... 

    // Step 5 
} 

這不是非常優雅,易於閱讀的海事組織。我想將它濃縮到如下所示。

for(Job aJob: jobs){ 
    step1(); 
    step2(); 
    .. 
    step5(); 
} 

step1(){ 
    try{ 
     ... 
    } 
    catch(Exception e){ 
     raiseTicket(errMsg1,e); 
     break; 
    } 
} 

step2(){ 
} 
... 

有人可以拋出一些關於如何改善這個計劃?請注意,返回值或將其存儲在方法參數中也可能不起作用,因爲試圖在此實現的目標是避免執行break所需的鍋爐代碼,並將它們整齊地打包在一個可讀的方法中。

回答

0

讓步驟拋出一個特定的異常,讓循環代碼處理它!

用下面的異常類

class StepExecutionException extends RuntimeException { 
    StepExecutionException(String message, Throwable cause) { 
     super(message, cause); 
    } 

    void raiseTicket() { 
     // Code that raises the ticket ... 
     // The message can be retrieved with getMessage(). 
     // The cause can be retrieved with getCause(). 
    } 
} 

,你可以很容易地實現與代碼的步驟:

void step1() { 
    try { 
     ... 
    } catch(Exception e) { 
     throw new StepExecutionException("Step 1", e); 
    } 
} 

現在你的循環代碼如下所示:

for (Job aJob : jobs) { 
    try { 
     step1(); 
     step2(); 
     ... 
    } catch (StepExecutionException see) { 
     see.raiseTicket(); 
    } 
} 
+0

我喜歡這個解決方案。我看到Dat Nguyen也提出了同樣的答案。因此看起來像它的一個常見問題,並且有解決它的設計模式。 –

+0

我可以問,爲什麼使用RuntimeException而不是檢查異常? –

+0

'StepExecutionException'是一個檢查異常:)看到這個SO線程的一些更多信息:http://stackoverflow.com/questions/6115896/java-checked-vs-unchecked-exception-explanation –

1

首先,break不會中斷當前迭代,而是整個循環。你需要使用continue來實現。但是由於拋出的異常會跳過其餘的步驟,在這種情況下,您不需要任何額外的語句。

爲什麼不使用這樣的東西?

// create list with errorMessages in the following order: errMesFor1, errMesFor2,..., errMesFor5 
List<String> messageList = new ArrayList<>(); 
messageList.add(errMesFor1); 
messageList.add(errMesFor2); 
messageList.add(errMesFor3); 
messageList.add(errMesFor4); 
messageList.add(errMesFor5); 

for(Job aJob: jobs){ 
    // create list that holds successfully created objects 
    List<Obj> objList = new ArrayList<>(); 
    try { 
      Obj objRet1 = method1(); 
      // use objRet1; 
      list.add(objRet1); 
      Obj objRet2 = method2(); 
      // use objRet2; 
      list.add(objRet2); 
      Obj objRet3 = method3(); 
      // use objRet3; 
      list.add(objRet3); 
      Obj objRet4 = method4(); 
      // use objRet4; 
      list.add(objRet4); 
      Obj objRet5 = method5(); 
      // use objRet5; 
      list.add(objRet5); 
     } 
     catch(Exception e){ 
      // retrieve message for the first element that was not successfully added to the object list, hence the one that threw error 
      raiseTicket(messageList.get(objList.size()),e); 
     } 

這樣,你只需要編寫try-catch塊一次。

list中組織郵件也很好(或者您甚至可以在列表中編寫自定義wrapper class)。

唯一需要額外的是對象列表,以便您可以輕鬆找到引發異常的對象。

+0

謝謝指出。我想說'繼續',但我錯誤地輸入了'break' –

1

如果發生錯誤,你可以做的就是在每一步中拋出一個檢查異常,然後在for循環中捕獲檢查的異常。事情是這樣的:

class StepException extends Exception {...} 

for (Job aJob: jobs) { 
    try { 
    step1(); 
    step2(); 
    ... 
    step5(); 
    } catch (StepException se) { 
    // do something, e.g. print error to console 
    // the for loop will keep going when this occurs 
    } 
} 

step1() throws StepException { 
    try { 
     ... 
    } catch (Exception e) { 
     raiseTicket(...); 
     throw new StepException(e); 
    } 
} 

// similar to step2(), ..., step5() 
+0

我喜歡這個解決方案。但自從Seelenvirtuose首先提供了相同的答案,我接受了他的答案。 –

0

按Java基礎知識沒有人可以使用斷點外循環或切換

的情況下,你不能從堆棧存儲器打破環路的方法是代表堆棧存儲器項其中循環在另一個堆棧條目中,而方法在其他堆棧條目中。

1

一種可能解決方案可能是:

for (Job job : jobs) { 
    AtomicInteger step = new AtomicInteger(); 
    try { 
     Obj result = executeJob(step,() -> method1()); 
     // do something with result 
     result = executeJob(step,() -> method2()); 
     // do something with result 
     result = executeJob(step,() -> method3()); 
     // do something with result 
    } catch (Exception e) { 
     raiseTicket(errorMessages.get(step.get()), e); 
    } 
} 

private Obj executeJob(AtomicInteger step, Supplier<Obj> supplier) { 
    step.incrementAndGet(); 
    return supplier.get(); 
} 

errorMessagesMap<Integer, String>