https://habr.com/ru/post/221723/ + хороший комментарий https://habr.com/ru/post/221723/#comment_7555889
тезисы комментария:
- Ценность исключений в раскрутке стека.
- Исключения выкидывать только в случае критических ошибок, в остальных случаях - обрабатывать ошибку в той же функции, либо как можно блмже к ней, либо возвращать код ошибки.
- библиотеки не знают, критический ли у них случай, это знает только высокоуровневый код, поэтому библиотеки не должны выбрасывать исключения. Можно только чтобы указать на неправильное использование библиотеки.
https://wiki.c2.com/?ExceptionPatterns
Чтобы обернуть один эксепшн в другой, нужно использовать Chained exceptions: https://docs.oracle.com/javase/tutorial/essential/exceptions/chained.html
ConvertExceptions(https://wiki.c2.com/?ConvertExceptions)
Нижележащие слои в своем "верхнем" коде должны преборазовывать все свои low-level исключения в меньшее множество исключений, понятных клиенту, а свои low-level привязывать к ним как chained exception. Тогда клиент получит понятное ему исключение, а вместе с тем сможет докопаться до истинной причины.
Другой вариант - не приязывать низшее исключение, а логировать. Мотивация - коду не нужно знать, почему именно что-то произошло, а разработчику, который посмотрит в лог - нужно. Аргумент против - пусть вышележащий хэндлер исключения разберется, что с ним делать. Иначе может быть такое, что мы залогировали, а хэндлер разобрался с исключением и в результате у нас в логе ошибка, а проблема решена.
Метод, выбрасывающий исключение, перед выбрасыванием должен привести свой объект в состояние, удовлетворяющее инвариантам класса. Иначе говоря, подчистить мусор, который был создан в той части метода, которая успела выполниться до выбрасывания исключения.
Причем вот здесь http://www.artima.com/intv/handcuffs.html Андерс Хейльсберг утверждает, что подчищание за собой должно осуществляться в try/finally в разных местах по коду, а try/catch должен быть в одном месте, централизованный.
Anders Hejlsberg: It is funny how people think that the important thing about exceptions is handling them. That is not the important thing about exceptions. In a well-written application there's a ratio of ten to one, in my opinion, of try finally to try catch. Or in C#, using statements, which are like try finally.
Bill Venners: What's in the finally?
Anders Hejlsberg: In the finally, you protect yourself against the exceptions, but you don't actually handle them. Error handling you put somewhere else. Surely in any kind of event-driven application like any kind of modern UI, you typically put an exception handler around your main message pump, and you just handle exceptions as they fall out that way. But you make sure you protect yourself all the way out by deallocating any resources you've grabbed, and so forth. You clean up after yourself, so you're always in a consistent state. You don't want a program where in 100 different places you handle exceptions and pop up error dialogs. What if you want to change the way you put up that dialog box? That's just terrible. The exception handling should be centralized, and you should just protect yourself as the exceptions propagate out to the handler.
https://community.oracle.com/docs/DOC-983543
При обработке сообщения его можно либо логировать, либо пробрасывать наверх, но никогда не Log And Throw!
Никогда не пишите в Java throws Exception
.
public void foo() throws MyException, AnotherException, SomeOtherException, YetAnotherException {
Бросать несколько checked-исключений можно только если мы знаем, что клиент их будет по разному обрабатывать. Иначе имеет смысл конвертировать их в одно исключение (см. ConvertExceptions)
catch (NoSuchMethodException e) { LOG.error("Blah", e); return null; }
Вместо этого нужно пробрасывать (не логируя, см. LogAndThrow) исключение наверх, пусть клиент разберется. null возвращаем в не-исключительном коде.
finally никогда не должен выбрасывать исключения.
Всегда нужно стараться группировать сообщения в одну строку. Держать в голове, что логи могут отправляться на сервер и тогда 2 соседние строчки могут разлететься далеко друг от друга.
https://community.oracle.com/docs/DOC-983219
- Be specific
- Throw Early - пытаться обнаруживать ошибки и стрелять исключения как можно раньше. Например, проверять входные аргументы на null. Проверять, что файл нормально открылся преждем чем пытаться в него писать. И так далее.
- Catch Late - не обрабатывать исключения раньше, чем требуется.
https://habr.com/ru/post/128397/
Если функции подают неправильные данные, то она должна сразу выбросить исключение.
Если же данные правильны, то она должна либо выполнить работу, либо умереть (выбросив исключение), но опять же в случае выброса нужно восстановить инварианты класса.
Из принципа следует и то, что нельзя возвращать null или пустую коллекцию при исключениях, потому что так клиент не узнает, что работа не была выполнена. Пусть голова болит у клиента, пробросим исключение ему.