Как обрабатывать исключения в Java

У меня есть сценарий, который обрабатывает миллионы данных. Те же данные повреждены, поэтому используемая мной структура дает сбой и выдает исключение. Я зависим от структуры, которую не могу изменить/обновить. Я использую его как есть. Каждый раз, когда я использую функцию этого фреймворка, я использую try/catch. Поэтому я использую много блоков try/catch, в результате код становится нечитаемым. Я хочу избавиться от блоков try/catch и обрабатывать исключения отдельно от моего кода.

Я хочу иметь глобальный обработчик исключений, поэтому всякий раз, когда платформа выдает исключение, оно должно перехватывать и регистрировать, а цикл обработки данных должен продолжаться. Существуют веб-фреймворки, такие как Spring и Jersey, которые имеют глобальный обработчик исключений. Я хочу аналогичного поведения для сценария.

Я попробовал Thread.UncaughtExceptionHandler, но по умолчанию UncaughtExceptionHandler останавливает процесс при возникновении исключения, поэтому он не срабатывает.

В настоящее время мой код выглядит так. Я хочу избавиться от блоков try/catch.

public static void main(String[] args)  throws FrameworkException {
    List<Element> elements = new ArrayList<>(); //Millons of data
    processItems(elements)
}

public void processItems(List<Element> items) throws FrameworkException{
    for (int i = 0; i < elements.size(); i++) {
        try{
            framework.doSomething(elements.get(i));
        }
        catch(FrameworkException e){
            // handle
        }

        // . . .

        try{
            framework.doDifferentThing(elements.get(i));
        }
        catch(FrameworkException e){
            // handle
        }

        // . . .
    }

    System.out.println("Processing completed.");
}

Код моей мечты и исключения обрабатываются глобально.

public void processItems(List<Element> items) throws FrameworkException{
    for (int i = 0; i < elements.size(); i++) {
            framework.doSomething(elements.get(i));

            // . . .

            framework.doDifferentThing(elements.get(i));

             // . . .
    }
    System.out.println("Processing completed.");
}

«он должен перехватывать и регистрировать, и цикл обработки данных должен продолжаться». Тогда это звучит так, будто вы хотите перехватить и обработать исключение внутри цикла. Что вы, судя по всему, уже делаете. Можете ли вы уточнить, почему ваша попытка не работает должным образом?

David 26.03.2024 13:35

Я использую множество блоков try/catch, в результате код становится нечитаемым. Я хочу избавиться от блоков try/catch и обрабатывать исключения отдельно от моего кода.

Kaan Ateşel 26.03.2024 13:37

Если вы хотите перехватить и обработать исключение внутри цикла, то для этого вам нужно будет перехватить и обработать исключение внутри цикла. Если проблема в том, что в этом цикле слишком много блоков try/catch, то... Почему их так много? Чем они отличаются друг от друга? Пробовали ли вы их объединить? У вас уже есть работающий код, и вы просто ищете предложения по его рефакторингу и сокращению?

David 26.03.2024 13:39

@KaanAteşel вы не можете «удалить всю отдельную обработку» И обрабатывать их все «отдельно». Но что мешает вам иметь один простой блок try-catch?

Stultuske 26.03.2024 13:39

Если все, что вы делаете, это регистрируете исключение и продолжаете цикл, то почему бы просто не использовать одну попытку?

Slaw 26.03.2024 13:41

Мне приходится регистрировать разные объекты при каждой попытке. Я попробую объединить их еще раз, спасибо за ответы.

Kaan Ateşel 26.03.2024 13:43

Обратите внимание, что у одного try может быть несколько catch.

Slaw 26.03.2024 13:45

Если framework.doSomething(elements.get(i)); выдает исключение, вы все равно хотите попробовать вызвать framework.doDifferentThing(elements.get(i)); на том же объекте? Или вы хотите прекратить обработку этого объекта в момент возникновения какого-либо исключения и перейти к следующему объекту?

k314159 26.03.2024 13:50

Я хочу прекратить обработку элемента и перейти к следующему. Например, в веб-фреймворках, таких как Spring или Jersey, есть глобальный обработчик исключений, мне нужен аналогичный тип обработки исключений.

Kaan Ateşel 26.03.2024 13:57

@KaanAteşel: «Глобальный» будет вне цикла. Если вы хотите обрабатывать исключения внутри цикла, вам следует сделать это внутри цикла. Похоже, вы просто неправильно понимаете, как работают исключения и стек вызовов в целом.

David 26.03.2024 14:08

@Дэвид, спасибо за ответы, я проведу дополнительное исследование.

Kaan Ateşel 26.03.2024 14:11

Похоже, вам просто нужен один блок try-catch внутри цикла, начиная со строки, следующей сразу за оператором for (т. е. весь ваш цикл — это одна большая попытка).

k314159 26.03.2024 14:14

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

Roman C 26.03.2024 14:18

Вам нужно объяснить более подробно: «Мне нужно регистрировать разные объекты при каждой попытке».

tgdavies 26.03.2024 22:04
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
14
104
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете определить функциональный интерфейс для представления действий, выполняемых над любым Element, который может вызвать FrameworkException. Затем вам просто нужно реализовать метод, который принимает как действие, так и текущий элемент. Этот метод инкапсулирует логику try-catch и применяет действие к элементу.

@FunctionalInterface
public interface ElementAction {
  void execute(Element element) throws FrameworkException;
}
public void tryAction(ElementAction action, Element element) {
  try {
    action.execute(element);
  } catch (FrameworkException e) {
    // do whatever you usually do for exceptions
  }
}

Таким образом, вы можете сделать свой processItems чище следующим образом:

public void processItems(List<Element> items) {
  for (Element item : items) {
    tryAction(element -> framework.doSomething(item), item);

    // . . .

    tryAction(element -> framework.doDifferentThing(item), item);

    // . . .
    }

    // cont.
}

редактировать (просто прочитайте комментарии к основному сообщению):

Вы можете расширить метод tryAction, передав BiConsumer, который принимает Element и FrameworkException для пользовательского входа в систему.

@FunctionalInterface
public interface ExceptionLogger extends BiConsumer<Element, FrameworkException> {}

Затем вы добавите его в метод tryAction:

public void tryAction(ElementAction action, Element element, ExceptionLogger logger) {
  try {
    action.execute(element);
  } catch (FrameworkException e) {
    logger.accept(element, e);
  }
}

Затем в свой processItems вы должны добавить свой способ регистрации исключения:

public void processItems(List<Element> items) {
  for (Element item : items) {
    tryAction((
      element -> framework.doSomething(item), 
      item,
      (element, e) -> System.err.println("this error " + e.getMessage())
    );

    // . . .

    tryAction(
      element -> framework.doDifferentThing(item),
      item,
      (element, e) -> System.err.println("that error " + e.getMessage())
    );

    // . . .
    }

    // cont.
}

(при условии, что вы используете Java 8+, что вам действительно нужно в наши дни)

Похоже, вы хотите, чтобы цикл продолжался всякий раз, когда возникает исключение платформы:

for (Element item : items) {
    try {
        framework.doSomething(item);

        // ...

        framework.doDifferentThing(item);
    } catch (FrameworkException | SomeOtherFrameworkException e) {
        logger.log(Level.INFO, "Corrupted element " + item, e);
    }
}

Это позволяет вашей логике выглядеть непрерывной, без визуального разделения на несколько блоков catch.

Вам не следует использовать какую-то магическую аннотацию, чтобы скрыть блоки try/catch от других разработчиков. Распространение вашей логики на другие места без какой-либо ссылки на них только значительно затруднит дальнейшее обслуживание.

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

Другие вопросы по теме

Похожие вопросы