2010-04-23 61 views
4

有些任務不應該並行完成(例如打開文件,讀取,寫入和關閉,這裏有一個命令。 ..)非順序任務中的Java異常處理(模式/良好實踐)

但是......有些任務更像是SHOPING列表,我的意思是,他們能有一個理想的訂單,但它不是在通信或裝載independient司機等一must..example ..

對於那種任務, 我想知道一個java的最佳實踐或管理例外模式..

java的簡單方法是:

getUFO { 
     try { 
      loadSoundDriver(); 
      loadUsbDriver(); 
      loadAlienDetectorDriver(); 
      loadKeyboardDriver();  
    } catch (loadSoundDriverFailed) { 
    doSomethingA; 
    } catch (loadUsbDriverFailed) { 
     doSomethingB; 
    } catch (loadAlienDetectorDriverFailed) { 
     doSomethingC; 
    } catch (loadKeyboardDriverFailed) { 
     doSomethingD; 
    } 
} 

但是關於其在動作中的一個例外,但希望 嘗試下一個什麼樣的人?

我以爲這種做法,但似乎並沒有成爲例外很好的利用 我不知道,如果它的工作原理,沒關係,這真的可怕

getUFO { 
     Exception ex=null; 
try { 
     try{ loadSoundDriver(); 
     }catch (Exception e) { ex=e; } 
     try{ loadUsbDriver(); 
     }catch (Exception e) { ex=e; } 
     try{ loadAlienDetectorDriver(); 
     }catch (Exception e) { ex=e; } 
     try{ loadKeyboardDriver() 
     }catch (Exception e) { ex=e; } 

     if(ex!=null) 
     { throw ex; 
     } 
    } catch (loadSoundDriverFailed) { 
    doSomethingA; 
    } catch (loadUsbDriverFailed) { 
     doSomethingB; 
    } catch (loadAlienDetectorDriverFailed) { 
     doSomethingC; 
    } catch (loadKeyboardDriverFailed) { 
     doSomethingD; 
    } 
} 

似乎並不複雜找到這樣做的。我還沒有

感謝您的任何意見的確

+0

問題的核心部分是如何使代碼像第一個一樣乾淨,但功能與第二個一樣(它不會中斷過程,讓我們嘗試下一個語句)。 當然,如果不僅讓我們去嘗試下一個,但如果它讓我們「重試」失敗的...... – 2010-04-23 16:38:28

回答

1

IMO,爲你的情況下,更好的做法,如果異常是「忽略」最好是「loadSoundDriver」方法捕獲異常並返回一個錯誤。

然後在加載內容的函數中,您可以記錄所有錯誤,並在序列結束時決定如何處理它們。 [編輯] 事情是這樣的:

// init 
MyError soundErr = loadSoundDriver(); 
MyError otherErr = loadOtherDriver(); 

if(soundErr!=null || otherErr !=null){ 
// handle the error(s) 
} 
5

考慮execute around idiom

另一個選項(並不完全相同,它只是將它們分開)是在單獨的線程中完成每個任務。

編輯:

這裏是什麼樣的事情,我心裏有:

public interface LoadableDriver { 
    public String getName(); 
    public void loadDriver() throws DriverException; 
    public void onError(Throwable e); 
} 

public class DriverLoader { 
    private Map<String, Exception> errors = new HashMap<String, Exception>(); 

    public void load(LoadableDriver driver) { 
     try { 
      driver.loadDriver(); 
     } catch (DriverException e) { 
      errors.put(driver.getName(), e); 
      driver.onError(e); 
     } 
    } 

    public Map<String, Exception> getErrors() { return errors; } 
} 

public class Main { 
    public void loadDrivers() { 
      DriverLoader loader = new DriverLoader(); 
      loader.loadDriver(new LoadableDriver(){ 
       public String getName() { return "SoundDriver"; } 
       public void loadDriver() { loadSoundDriver(); } 
       public void onError(Throwable e) { doSomethingA(); } 
      }); 
      //etc. Or in the alternative make a real class that implements the interface for each driver. 
      Map<String, Exception> errors = loader.getErrors(); 
      //react to any specific drivers that were not loaded and try again. 
     } 
} 

編輯:這是一個乾淨的Java版本最終會看起來像,如果你實現了驅動程序,因爲類(是Java OO範例在這裏預期的恕我直言)。該Main.loadDrivers()方法會改變這樣的:

 public void loadDrivers(LoadableDriver... drivers) { 
      DriverLoader loader = ... 
      for(LoadableDriver driver : drivers) { 
       loader.load(driver); 
      } 
      //retry code if you want. 
      Set<LoadableDriver> failures = loader.getErrors(); 
      if(failures.size() > 0 && tries++ > MAX_TRIES) { 
       //log retrying and then: 
       loadDrivers(drivers.toArray(new LoadableDriver[0])); 
      } 
     } 

我當然不再使用地圖,因爲對象將是自給自足的(你可以擺脫的getName()的方法爲好,但可能應該重寫toString()),所以錯誤只是返回一個集合重試。如果每個驅動程序都有責任知道它應該重試的頻率,那麼可以使重試代碼變得更簡單。

Java看起來不如完美的C++模板好,但這是Java語言設計的選擇 - 比起復雜的語言特性更喜歡簡單,如果做得不好,可能會使代碼難以維持一段時間。

+0

@Dave,雖然沒有清理,但是有異常處理同樣的事情(因爲在你需要周圍處理它)。我會盡力把我腦海中所想的東西剔除出去。 – Yishai 2010-04-23 16:51:53

+0

這種方法看起來確實更復雜,我試圖認爲沒有任何方法可以用java來清理它(在C++中我可以編寫一些宏來至少保持可見代碼的非常乾淨) – 2010-04-23 19:01:48

+0

那麼它肯定是冗長的(請參閱我的鏈接,Jon Skeet在Java中解釋了爲什麼它非常痛苦),但它處理您要求的額外場景 - 重試和自定義錯誤處理。如果目標是讓這個例程更好,那麼首先讓每個驅動程序實現該接口。然後它會開始變得非常乾淨。讓驅動程序能夠成爲Map中的一個鍵,甚至更清晰,然後將加載轉換爲遞歸方法,甚至更好。這段代碼在你的版本中獲得的優勢在於,當添加驅動程序時,它比其他版本更容易出錯。我會寫一個「乾淨的版本」。 – Yishai 2010-04-23 20:32:19

3

試試這個:

protected void loadDrivers() { 
    loadSoundDriver(); 
    loadUsbDriver(); 
    loadAlienDetectorDriver(); 
    loadKeyboardDriver();  
} 

然後:

protected void loadSoundDriver() { 
    try { 
    // original code ... 
    } 
    catch(Exception e) { 
    soundDriverFailed(e); 
    } 
} 

protected void soundDriverFailed(Exception e) { 
    log(e); 
} 

這讓子類有機會去改變。例如,一個子類可以實現在一個單獨的線程中加載每個驅動程序。主類不需要關心驅動程序的加載方式,主類的任何用戶也不應該這樣做。

+0

+1您的解決方案實際上與我的相同,只是更好:) – Virgil 2010-04-23 16:27:26

0

只用其自己的try/catch塊包圍每一個加載操作。

try { 
    loadSoundDriver(); 
} catch (loadSoundDriverFailed) { 
    doSomethingA; 
} 

try { 
    loadUsbDriver(); 
} catch (loadUsbDriverFailed) { 
    doSomethingB; 
} 

    // ... 

因此,你可以自己來處理每個異常並繼續處理奧德操作。

+0

我已經把這種方式,像醜陋的,我正在尋找一個乾淨的替代品 – 2010-04-23 18:58:24