Является ли в Java использование throws Exception вместо бросания нескольких конкретных исключений хорошей практикой?

Надеюсь, вы найдете это полезным.

HTML:

<html>
<head>
    <link rel = "stylesheet" href = "test.css">
<body>

</body>
<script src = "test.js"></script>
</head>
</html>

JAVASCRIPT:

var tableString = "<table>",
    body = document.getElementsByTagName('body')[0],
    div = document.createElement('div');

for (row = 1; row < 101; row += 1) {

    tableString += "<tr>";

    for (col = 1; col < 11; col += 1) {

        tableString += "<td>" + "row [" + row + "]" + "col [" + col + "]" + "</td>";
    }
    tableString += "</tr>";
}

tableString += "</table>";
div.innerHTML = tableString;
body.appendChild(div);
13
задан Cœur 23 July 2017 в 10:15
поделиться

14 ответов

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

Если вы имеете в виду такие классы, как интерфейс Controller , который является сигнатурой метода, например

handleRequest(HttpServletRequest request, HttpServletResponse response) 
   throws Exception

, то это вероятно потому, что с точки зрения классов Spring, которые в ваш контроллер (например, DispatcherServlet ), им все равно, какой тип исключения вызывает ваш код - код библиотеки, такой как DispatcherServlet , должен знать только, что этот класс может вызывать Exception и, следовательно, может обрабатывать Exception в общем случае.

Другими словами, DispatcherServlet не выполняет ' Не нужно знать, какие именно типы исключений может генерировать ваш контроллер - он будет рассматривать любой из них как «ошибку». Вот почему сигнатура метода вызывает исключение .

Теперь авторы API могли бы использовать в сигнатуре пользовательский тип исключения как SpringMvcException , но это будет иметь только эффект вынудить вас обрабатывать любые проверенные типы исключений в вашем методе handleRequest и просто обернуть их, что является утомительным стандартным кодом для создания работы. Итак, поскольку почти все, что есть в Spring, спроектировано так, чтобы сделать его максимально простым и легким для интеграции, им проще указать, что метод интерфейса просто выдает исключение .

будет рассматривать любой из них как «ошибку». Вот почему сигнатура метода вызывает исключение .

Теперь авторы API могли бы использовать в сигнатуре пользовательский тип исключения как SpringMvcException , но это будет иметь только эффект вынудить вас обрабатывать любые проверенные типы исключений в вашем методе handleRequest и просто обернуть их, что является утомительным стандартным кодом для создания работы. Итак, поскольку почти все, что есть в Spring, спроектировано так, чтобы сделать его максимально простым и легким для интеграции, им проще указать, что метод интерфейса просто выдает исключение .

будет рассматривать любой из них как «ошибку». Вот почему сигнатура метода вызывает исключение .

Теперь авторы API могли бы использовать в сигнатуре пользовательский тип исключения как SpringMvcException , но это будет иметь только эффект вынудить вас обрабатывать любые проверенные типы исключений в вашем методе handleRequest и просто обернуть их, что является утомительным стандартным кодом для создания работы. Итак, поскольку почти все, что есть в Spring, спроектировано так, чтобы сделать его максимально простым и легким для интеграции, им проще указать, что метод интерфейса просто выдает исключение .

авторы API могли бы заставить подпись использовать настраиваемый тип исключения как SpringMvcException , но это привело бы только к тому, что вы заставили бы вас обрабатывать любые проверенные типы исключений в вашем методе handleRequest и просто обернуть их, что является утомительным шаблоном кода для работы. Итак, поскольку почти все, что есть в Spring, спроектировано так, чтобы сделать его максимально простым и легким для интеграции, им проще указать, что метод интерфейса просто выдает исключение .

авторы API могли бы заставить подпись использовать настраиваемый тип исключения как SpringMvcException , но это привело бы только к тому, что вы заставили бы вас обрабатывать любые проверенные типы исключений в вашем методе handleRequest и просто обернуть их, что является утомительным шаблоном кода для работы. Итак, поскольку почти все, что есть в Spring, спроектировано так, чтобы сделать его максимально простым и легким для интеграции, им проще указать, что метод интерфейса просто выдает исключение .

16
ответ дан 1 December 2019 в 06:07
поделиться

Сложно.

В идеале указание исключения является частью контракта, сообщая пользователю, какие исключения могут ожидаться. Это помогает им решить, что обрабатывать, а что нет.

Хотя при написании фреймворка или библиотеки сказать невозможно -

abstract T func (...) выдает A, B, C;

потому что любой класс, расширяющий контейнер func (...), может потенциально переопределить и func.

Мне самому пришлось использовать более свободную спецификацию 'throws Exception', но, как правило,

  • Обеспечьте строгое исключение спецификации для частных методов (в контексте этого обсуждения я считаю методы частными в том смысле, что их контракт неизменяем), свободная спецификация для всех остальных.
0
ответ дан 1 December 2019 в 06:07
поделиться

Я действительно удалил проверенные исключения из компилятора.

Это работает лучше, чем можно было бы предположить.

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

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

1
ответ дан 1 December 2019 в 06:07
поделиться

Создание исключения также может вызвать множество проблем с управлением транзакциями в J2EE. Использование исключения отлова - чистое зло!

Я не награждаю вас котятами!

0
ответ дан 1 December 2019 в 06:07
поделиться

In my opinion yes, because this allows you to throw any exception you want.

As your program grows, you might need to throw a different exception than you had originally thought about. If you defined each individual exception type, you would have to modify the methods signature and in turn modify all methods that called it to properly process the new exception.

Just using 'throws Exception' allows any method calling your method to properly handle any methods you have listed, but whenever you add new exceptions into your function, it won't break these other methods. (Though you should probably update them to handle the new exception, but this is not required.)

1
ответ дан 1 December 2019 в 06:07
поделиться

Да и нет. да, «удобно» просто выбросить или перехватить одно исключение и все готово, но это действительно мешает вам при любой попытке изящного восстановления после исключения. С некоторыми исключениями можно и нужно обращаться аккуратно, чтобы ваша программа не умерла ужасной смертью. Если метод просто выдает исключение, я понятия не имею, что пошло не так, и поэтому у меня нет никакой надежды исправить и восстановить проблему.

Одна из возможных ошибок и решений:

при синтаксическом анализе целых чисел - NumberFormatException . У нас может быть значение по умолчанию

Нижняя строка,

0
ответ дан 1 December 2019 в 06:07
поделиться

Брайан Гетц затрагивает некоторые из этих проблем здесь . Также см. Эффективная Java 2-е издание, автор Джош Блох. Он посвящает исключениям целый раздел. Кроме того, Род Джонсон, основатель Spring Framework, подробно описывает свои мысли об обработке исключений Java в Проектирование и разработка J2EE . Вы можете согласиться или не согласиться с его философией обработки исключений, но, по крайней мере, это может иметь больше смысла, почему они приняли такие решения.

alt text
(источник: sun.com )
alt text

1
ответ дан 1 December 2019 в 06:07
поделиться

ИМХО, все обсуждения и рекомендации по дизайну говорят хорошие вещи о том, что нужно делать В ОБЩЕМ, и у них есть принцип, который их поддерживает. Но обычно эти рекомендации не применимы ко всем случаям.

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

2
ответ дан 1 December 2019 в 06:07
поделиться

Нет.

Выдача исключения заставляет вызывающий код перехватить исключение, чего они, вероятно, не захотят делать по разным причинам.

3
ответ дан 1 December 2019 в 06:07
поделиться

Вот проблема с генерированием определенных исключений ... Предположим, кто-то расширяет ваш класс и хочет переопределить ваш метод. Предположим, их новая реализация должна генерировать исключение другого типа. (Как вы когда-нибудь сможете предсказать, какие исключения может потребоваться выбросить переопределяющий метод?) Человек, пишущий переопределяющий метод, имеет только два варианта: 1) обработать исключение самостоятельно (вероятно, плохой выбор) или 2) обернуть реальное исключение в одном из допустимых типов исключений и повторно выбросить.

Но вариант 2 имеет две проблемы. Во-первых, когда вы сбрасываете свои исключения в файлы журнала, вы получаете длинные уродливые цепочки вложенных исключений. Что еще более важно, вы потеряете способность перехватывать определенные исключения. Например, предположим, что переопределяющий метод вызывает другой метод, который общается с базой данных и генерирует исключение DeadlockException, если результирующий SQL вызвал взаимоблокировку. Метод переопределения должен перехватить это исключение, заключить его в один из допустимых типов и повторно вызвать. Это делает невозможным перехват и обнаружение исключения DeadlockException для кода, расположенного дальше по стеку.

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

Кстати, для людей, которым не нравятся отмеченные исключения, я не люблю Мне нравится идея использования RuntimeException повсюду. Проблема в том, что вам, вероятно, потребуется включить стороннюю библиотеку, которая использует Exception, а не RuntimeException. Затем ваш код должен будет перехватить все исключения из библиотеки и обернуть их в RuntimeException. Это создает беспорядок.

Итак, если бы я снова начинал проект Java с нуля, я бы просто объявил, что каждый метод генерирует исключение.

7
ответ дан 1 December 2019 в 06:07
поделиться

Вам необходимо различать общий код и более конкретный код.

Рассмотрим возвращаемые типы функций в качестве аналогии. Если вы пишете такой класс, как «ArrayList», вы хотите, чтобы он был очень общим, поэтому параметры и возвращаемые значения часто являются общими »

Клинт Миллер поднимает важный вопрос о незнании того, как класс может быть расширен. Я признаю, что это проблема с конкретизацией ваших исключений. Но переход оттуда к «просто сделать все универсальным исключением» - это слишком легко сдаться. Это все равно, что сказать, что, поскольку кто-нибудь когда-нибудь может расширить нашу функцию getRetiredEmployees, чтобы в некоторых случаях возвращать EmployeeSpouse вместе с Employee, мы должны просто отказаться и сделать возвращаемый тип Object. Если это код, который вы используете внутри себя и контролируете, это не проблема: если вам нужно добавить новое исключение в функцию, добавьте его. Если это API, который вы публикуете для всего мира, то да, проблема гораздо сложнее. Я бы сказал, что общее решение - попытаться рационально подумать, какие исключения имеют смысл, и включить их все, даже если они не все в настоящее время реализованы. Если один из ваших клиентов делает что-то совершенно неожиданное, ну что ж, это проблема, на которую нет простого ответа.

Делать все универсальным - неправильный ответ, потому что это делает все трудным для понимания, трудным для поддержания, и трудно проверить точность.

1
ответ дан 1 December 2019 в 06:07
поделиться

Нет, абсолютно нет. Вы должны указать, какие исключения вы собираетесь выбросить, чтобы вызывающий мог поступать правильно с каждым из них. Если вы этого не сделаете, «throws Exception» будет передан вверх по цепочке, и лучшее, что могут сделать вызывающие, - это printStackTrace () и умереть.

Обновление: чтобы противостоять некоторым возражениям «что, если я отменю метод», Я бы пошел немного дальше и сказал, что каждый раз, когда у вас есть пакет, который генерирует исключения (в отличие от передачи исключения от вызывающей стороны), вы должны объявить класс исключения в этом пакете. Таким образом, если вы переопределяете мой "addToSchedule () throws ScheduleConflictException", вы вполне можете создать подкласс ScheduleConflictException, чтобы делать то, что вам нужно.

18
ответ дан 1 December 2019 в 06:07
поделиться

Список всех исключений. Таким образом:
* Четко определено, что МОЖЕТ пойти не так.
* Пользователи вашего класса могут ТОЧНО знать, какие исключения они должны обрабатывать.

Кроме того, замещающий метод должен делать то же самое, что и замещаемый, но другим способом. Следовательно, как у вас могло быть другое исключение, которое НЕ ЯВЛЯЕТСЯ подклассом уже созданного исключения? Вы не должны. Кроме того, вам НЕ СЛЕДУЕТ генерировать новые исключения в подклассе, поскольку подкласс должен быть в состоянии заменить его родительский класс, следовательно, если он передается как «p» в

public void method(Parent p);

, как «метод» узнает, что он должен обрабатывать какое-то новое исключение? В этом не должно быть необходимости. А это означает неправильный дизайн (либо родительского класса, либо подкласса).

1
ответ дан 1 December 2019 в 06:07
поделиться

ИМО, самая большая причина для того, чтобы не генерировать исключение, заключается в том, что оно заставляет наших клиентов перехватить (Исключение e) , если они действительно заинтересованы в каких-либо действиях.

Проблема с перехватом (Exception e) заключается в том, что Exception при установленном флажке также является суперклассом RuntimeException и поэтому заставляет клиента перехватить все RuntimeExceptions ] тоже.

К сожалению, здесь нет техники catch (CheckedException e). Предполагая, что ваш бедный клиент не нуждался в перехвате исключений RuntimeExceptions, он должен выполнить проверку instanceof и повторно выбросить его, если это исключение RuntimeException.

также является суперклассом RuntimeException и поэтому заставляет клиента перехватывать все исключения RuntimeException .

К сожалению, здесь нет техники перехвата (CheckedException e). Предполагая, что ваш бедный клиент не нуждался в перехвате исключений RuntimeExceptions, он должен выполнить проверку instanceof и повторно выбросить его, если это исключение RuntimeException.

также является суперклассом RuntimeException и поэтому заставляет клиента перехватывать все исключения RuntimeException .

К сожалению, здесь нет техники перехвата (CheckedException e). Предполагая, что ваш бедный клиент не нуждался в перехвате исключений RuntimeExceptions, он должен выполнить проверку instanceof и повторно выбросить его, если это исключение RuntimeException.

3
ответ дан 1 December 2019 в 06:07
поделиться
Другие вопросы по тегам:

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