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