简体   繁体   English

非顺序任务中的Java异常处理(模式/良好实践)

[英]Java exception handling in non sequential tasks (pattern/good practice)

There are some task that should't be done in parallel, (for example opening a file, reading, writing, and closing, there is an order on that...) 有些任务不应该并行完成(例如打开文件,读取,写入和关闭,有一个订单......)

But... Some task are more like a shoping list, I mean they could have a desirable order but it's not a must..example in communication or loading independient drivers etc.. 但是......有些任务更像是一个购物清单,我的意思是它们可能有一个理想的订单,但它不是必须的.​​.....例如通信或加载独立的驱动程序等。

For that kind of tasks, I would like to know a java best practice or pattern for manage exceptions.. 对于这类任务,我想知道一个用于管理异常的java最佳实践或模式。

The java simple way is: java的简单方法是:

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

But what about having an exception in one of the actions but wanting to try with the next ones?? 但是,如果在其中一个动作中有异常但想要尝试 下一个动作呢?

I've thought this approach, but don't seem to be a good use for exceptions I don't know if it works, doesn't matter, it's really awful !! 我认为这种方法,但似乎不是一个很好用的例外我不知道它是否有效,无所谓,这真的很糟糕

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;
  } 
}

seems not complicated to find a better practice for doing that.. I still didn't 找到更好的做法似乎并不复杂..我仍然没有

thanks for any advice 谢谢你的建议

Consider the execute around idiom . 考虑围绕习语执行

Another option (which isn't really all that different, it just decouples them more) is to do each task in a separate thread. 另一个选项(实际上并非完全不同,它只是将它们分离出来)是在一个单独的线程中完成每个任务。

Edit: 编辑:

Here is the kind of thing I have in mind: 这是我的想法:

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.
      }
 }

Edit: This is what a clean Java version would ultimately look like if you implemented the drivers as classes (which is what the Java OO paradigm would expect here IMHO). 编辑:如果您将驱动程序实现为类(这就是Java OO范例在此处预期的恕我直言),这就是干净的Java版本最终会是什么样子。 The Main.loadDrivers() method would change like this: 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]));
           }
       }

Of course I no longer use a map because the objects would be self-sufficient (you could get rid of the getName() method as well, but probably should override toString()), so the errors are just returned in a set to retry. 当然我不再使用地图,因为对象是自给自足的(你可以去除getName()方法,但可能应该覆盖toString()),所以错误只是在一组中返回重试。 You could make the retry code even simpler if each driver was responsible for knowing how often it should it retry. 如果每个驱动程序都有责任知道它应该重试的频率,那么您可以使重试代码更简单。

Java won't look as nice as a well done C++ template, but that is the Java language design choice - prefer simplicity over complex language features that can make code hard to maintain over time if not done properly. Java看起来不如一个做得好的C ++模板,但这是Java语言设计的选择 - 更喜欢简单而不是复杂的语言特性,如果不能正确完成,可能会使代码难以维护。

Try this: 尝试这个:

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

Then: 然后:

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

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

This gives subclasses a chance to change the behaviour. 这为子类提供了改变行为的机会。 For example, a subclass could implement loading each driver in a separate thread. 例如,子类可以实现在单独的线程中加载每个驱动程序。 The main class need not care about how the drivers are loaded, nor should any users of the main class. 主类不需要关心如何加载驱动程序,也不需要关心主类的任何用户。

IMO, for your case, if the exception is "ignorable" it's best if the "loadSoundDriver" method catches the exception and simply returns an error. IMO,对于你的情况,如果异常是“可忽略的”,最好是“loadSoundDriver”方法捕获异常并简单地返回错误。

Then in the function that loads stuff, you can record all the errors and at the end of the sequence, decide what to do with them. 然后在加载东西的函数中,您可以记录所有错误,并在序列的最后,决定如何处理它们。 [edit] Something like this: [编辑]像这样的东西:

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

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

Just surround every single load operation with its own try / catch block. 只需使用自己的try / catch块包围每个加载操作。

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

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

  // ...

So you can handle every exception by itself and continue processing the oder operations. 因此,您可以自己处理每个异常并继续处理oder操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM