Я записал класс, который загружает объекты конфигурации моего приложения и отслеживает их так, чтобы я мог легко выписать изменения или перезагрузить целую конфигурацию сразу с вызовом отдельного метода. Однако каждый объект конфигурации мог бы потенциально выдать исключение при выполнении IO, все же я не хочу тех ошибок отменить полный процесс, чтобы дать другим объектам все еще шанс перезагружать/писать. Поэтому я собираю все исключения, которые выдаются при итерации по объектам и хранят их в суперисключении, которое брошено после цикла, так как должно все еще быть обработано каждое исключение, и кто-то должен быть уведомлен относительно того, что точно пошло не так, как надо. Однако тот подход выглядит немного нечетным мне. Кто-то там с более чистым решением?
Вот некоторый код упомянутого класса:
public synchronized void store() throws MultipleCauseException
{
MultipleCauseException me = new MultipleCauseException("unable to store some resources");
for(Resource resource : this.resources.values())
{
try
{
resource.store();
}
catch(StoreException e)
{
me.addCause(e);
}
}
if(me.hasCauses())
throw me;
}
Если вы хотите сохранить результаты операций, которые, кажется, вы делаете так, как вы намеренно продолжаете, то создание исключения - это неправильный поступок. . Как правило, вы должны стремиться не беспокоить ничего, если генерируете исключение.
Я предлагаю передавать исключения или данные, полученные из них, в обратный вызов обработки ошибок по мере продвижения.
public interface StoreExceptionHandler {
void handle(StoreException exc);
}
public synchronized void store(StoreExceptionHandler excHandler) {
for (Resource resource : this.resources.values()) {
try {
resource.store();
} catch (StoreException exc) {
excHandler.handle(exc);
}
}
/* ... return normally ... */
]
Существуют руководящие принципы при разработке того, какие исключения должны генерироваться и когда, и два важных для этого сценария:
То, как вы переводите StoreException
в MultipleCauseException
, мне кажется разумным, хотя объединение разных типов исключений в один - не лучшая идея. К сожалению, Java не поддерживает общие Throwable
, поэтому, возможно, единственной альтернативой является создание вместо этого отдельного подкласса MultipleStoreException
.
Что касается создания исключений как можно раньше (чего вы НЕ делаете), я скажу, что в некоторых случаях можно изменить правило. Я чувствую, что опасность откладывать бросок возникает тогда, когда исключительные ситуации без надобности превращаются в цепную реакцию. По возможности вы хотите избежать этого и локализовать исключение в минимально возможной области.
В вашем случае, если имеет смысл концептуально рассматривать хранение ресурсов как несколько независимых задач , тогда может быть приемлемым «пакетную обработку» исключения, как вы это сделали. Однако в других ситуациях, когда задачи имеют более сложные отношения взаимозависимости, их объединение в одну кучу усложняет задачу анализа исключений.
В более абстрактном смысле, с точки зрения теории графов, я думаю, что можно объединить узел с несколькими бездетными потомками в один. Вероятно, неправильно объединять целое большое поддерево или, что еще хуже, циклический граф в один узел.