2010-04-23 3 views
4

Есть некоторая задача, которая должна выполняться параллельно (например, открытие файла, чтение, запись и закрытие, есть порядок на этом. ..)Обработка исключений Java в несекретных задачах (шаблон/хорошая практика)

но ... Некоторые задачи больше похожи на Shoping список, я имею в виду, они могут иметь желаемый порядок, но это не must..example в связи или загрузки independient водителей и т.д ..

Для такие задачи, Я хотел бы знать лучшие практики или шаблоны для управления исключениями.

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

Центральная часть вопроса заключается в том, как сделать код чистым, как первый, но функциональный как второй (он не прерывает процесс и позволяет попробовать следующие утверждения). И, конечно, было бы здорово, если бы не только попробовать попробовать следующие, но если он позволит «повторить» неудачные ... –

ответ

1

ИМО, для вашего случая, если исключение составляет «игнорируемые» лучше всего, если метод loadSoundDriver поймает исключение и просто возвращает ошибку.

Затем в функции, которая загружает материал, вы можете записать все ошибки и в конце последовательности решить, что с ними делать. [править] Что-то вроде этого:

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

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

Рассмотрим execute around idiom.

Другой вариант (который на самом деле не совсем то, что отличается, он просто отделяет их больше) состоит в том, чтобы выполнять каждую задачу в отдельном потоке.

Edit:

Вот такая вещь, я имею в виду:

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: Это то, что чистая версия Java будет в конечном итоге выглядеть, если вы реализовали драйверы как классы (которые это то, что ожидала бы парадигма Java OO здесь IMHO). В 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

+0

Этот подход кажется действительно более сложным, я искушаюсь думать, что нет никакого способа сделать его чистым с помощью java (в C++ я мог бы написать некоторые макросы, чтобы хотя бы сохранить видимый код очень чистым) –

+0

Ну, это определенно многословный (см. мою ссылку, где Джон Скит объясняет, почему это так болезненно в Java), но он обрабатывает дополнительные сценарии, которые вы запрашиваете, - повторите попытку и обработку пользовательских ошибок. Если цель заключалась в том, чтобы сделать эту процедуру приятной, начните с того, чтобы каждый драйвер реализовал этот интерфейс. Тогда это начнет становиться очень чистым. Попросите водителя быть ключом на Карте, даже более чистым, а затем снова включите загрузку в рекурсивный метод. Что этот код дает вам преимущество над вашей версией, так это то, что при добавлении драйверов, чем в другой версии, гораздо меньше ошибок. Я напишу «чистую версию». – Yishai

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

0

Просто объедините каждую операцию загрузки с помощью своего блока try/catch.

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

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

    // ... 

Таким образом, вы можете обрабатывать все исключения самостоятельно и продолжать обработку других операций.

+0

Я уже так поступил, как уродливый, я искал чистую альтернативу –

Смежные вопросы