Java - существует ли стандартный способ сбора исключений?
У меня есть Java-программа, которая анализирует несколько разных входных файлов. Даже если в этих входных файлах обнаружена ошибка, разбор может продолжаться и собирать еще несколько ошибок. Так что я хочу сделать, а не бросать и исключать и останавливать процесс синтаксического анализа, я хотел бы зарегистрировать исключение где-нибудь, а затем продолжить синтаксический анализ и собрать несколько других ошибок аналогичным образом, а затем, в конце концов, я хочу проверить, любые сообщения об ошибках и отказ или продолжение в зависимости от этого.
Конечно, я всегда могу сделать это вручную, написав ExceptionRegister или любые классы, но я хочу знать две вещи:
1) Есть ли проблема с этим подходом? Знаете ли вы какие-либо альтернативные варианты того, что я хочу делать?
2) Есть ли стандартный способ сделать это? (например, вместо прокатки собственных классов я хотел бы использовать встроенную функциональность, если это возможно)
Спасибо
EDIT: Я не знаю, почему, но кто-то просто удалил его ответ, прежде чем я принял его ответ. Во всяком случае, я думаю, что простые структуры данных должны работать. В принципе, я напишу класс исключения, который собирает несколько сообщений об ошибках. Затем я назову его методом throw, который запускается сам, если он зарегистрировал хотя бы одно сообщение об ошибке.
EDIT2: Вот дополнительные пояснения. Моя проблема не имеет никакого отношения к разбору. Анализ был всего лишь примером, потому что моя программа выполняет синтаксический анализ. Подумайте об этом: я запускаю алгоритм, и в случае ошибки я могу продолжить алгоритм для сбора большего количества ошибок, чтобы вместо того, чтобы печатать одну ошибку и когда она исправлялась, печатая вторую ошибку, я могу вместе печатать две ошибки.
Ответы
Ответ 1
Исключения действительно должны использоваться, когда вы больше не можете обрабатывать входные данные. Это особый случай, когда ваш код говорит: "Я сдаюсь, я пропускаю какую-то информацию, или я не был предназначен для этого". Это серая область о том, как определить такие случаи, но обычная философия, предложенная Биллом Веннерсом в этой (старой!) Статье:
Избегайте использования исключений для указания условий, которые могут быть разумно ожидаемый как часть типичного функционирования метода.
В вашем случае это похоже на то, что контент, который вы должны анализировать, может быть неправильным, но это ожидается вашей программой и не нарушает достаточно контракта, чтобы остановить разбор. С другой стороны, допустимое исключение было бы правильным использовать, если ошибка в синтаксисе ввода приводит к тому, что остальная интерпретация не выполняется, например.
Но люди по-прежнему используют исключение, потому что они довольно удобны для остановки выполнения и перехода по стеку, не вдаваясь в утомительные детали потока результатов возврата. Но у его коллеги они могут иметь хитрые результаты, поскольку вы оставляете какое-то состояние без присмотра в некоторых объектах.
Ваши требования скорее напоминают шаблон проверки, чем одно исключение, которое может привести к остановке обработки. Одно исключение, чтобы остановить всю обработку: если вы выбросите один, остальные будут проигнорированы. Но вы предложили, чтобы вы их собирали, а не бросали. Поэтому я бы сказал, в этом случае, зачем вообще использовать исключения? Кажется, вы хотите вернуть правильные результаты, а не останавливать выполнение программы.
Потому что, если вы все еще идете по этому пути, у вас может быть коллекция исключений для броска в конце. Кого вы бросаете? Какой из них имеет преимущество, в сборнике исключений, который вы создали?
Возьмем пример Eclipse, который имеет эту гигантскую платформу для обработки большого вклада плагинов коллекции. Они используют правильный канал связи для регистрации любых предупреждений и ошибок, либо в области проблем, либо посредством выполнения фоновой задачи. Последнее выполнение обычно возвращает объект IStatus или вариант. Основанный на этом объекте IStatus
, код, который получает статус, решает действовать на него.
Следовательно, лично я бы разработал аналогичный объект, который собирал бы все необходимые пользовательские ошибки (а не программные ошибки), что не нарушает выполнение программы и приемлемую часть контракта. Этот объект может содержать серьезность ошибки, ее источник, подсказку о том, как ее исправить (это может быть строка или даже метод, содержащий логику определения местоположения для показа ошибки или, возможно, частичное автоматическое исправление) и т.д. После выполнения выполнения результат синтаксического анализа получит эти статусные объекты и действует на него. Если есть ошибки, сообщите об этом пользователю через пользовательский интерфейс и запишите его также.
Итак, это в основном тот же подход, что и вы изначально предлагали, минус исключения и минус товар, прыгающий через стек, который может привести к неприятным побочным эффектам и очень трудно отладить ошибки.
Ответ 2
Думаю, теперь я понимаю. То, что вы на самом деле пытаетесь сделать, это собрать ошибки синтаксического анализа (которые вы представляете как исключения) и продолжить анализ текущего входного файла.
Нет стандартного способа сделать это:
"Реестр исключительных ситуаций" - это не что иное, как список дескрипторов ошибок синтаксического анализа... предположительно, какое-то исключение парсера. Если вы можете поймать исключение в соответствующей точке, тривиально добавить его в "регистр".
Трудная часть - это функциональность, о которой вы не говорите:
-
Как зафиксировать местоположение ошибки
-
Как заставить анализатор продолжать синтаксический анализ, когда он получает ошибку парсера.
Решения от них зависят от того, как вы реализовали свой парсер.
-
Если вы используете генератор синтаксического анализатора, есть хорошая вероятность, что документация PGS объясняет, как это реализовать.
-
Если вы выполняете парсер вручную, вам нужно будет свернуть свой собственный код, чтобы отслеживать места ошибок и выполнять восстановление синтаксических ошибок.
В принципе, я напишу класс исключения, который собирает несколько сообщений об ошибках. Затем я назову его методом throw, который запускается сам, если он зарегистрировал хотя бы одно сообщение об ошибке.
Это звучит как злоупотребление исключениями. Лучше всего собирать ошибки в списке, а затем создавать/вызывать исключение, если список не пуст. Используйте статический метод в вспомогательном классе, если вы хотите избежать дублирования кода.
Исключением, которое условно бросает себя, является (IMO) странным! И создание множества исключений, которые вы вряд ли бросите, скорее всего, будет неэффективным. (В зависимости от JVM, дорогостоящая часть исключений часто создает исключение и захватывает фреймы стека. Расходы могут быть значительными.)