简体   繁体   中英

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

The java simple way is:

 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). The Main.loadDrivers() method would change like this:

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

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.

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 {
  loadSoundDriver();
} catch (loadSoundDriverFailed) {
  doSomethingA;
} 

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

  // ...

So you can handle every exception by itself and continue processing the oder operations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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