Skip to content

Instantly share code, notes, and snippets.

@y-gagar1n
Last active August 28, 2020 07:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save y-gagar1n/6925ccda844400e42aa4234ca1c6beb8 to your computer and use it in GitHub Desktop.
Save y-gagar1n/6925ccda844400e42aa4234ca1c6beb8 to your computer and use it in GitHub Desktop.
exceptions

Ресурсы

https://www.researchgate.net/profile/Rebecca_Wirfs-Brock/publication/3248431_Toward_Exception-Handling_Best_Practices_and_Patterns/links/0deec52de98c15589e000000/Toward-Exception-Handling-Best-Practices-and-Patterns.pdf

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

Нижележащие слои в своем "верхнем" коде должны преборазовывать все свои low-level исключения в меньшее множество исключений, понятных клиенту, а свои low-level привязывать к ним как chained exception. Тогда клиент получит понятное ему исключение, а вместе с тем сможет докопаться до истинной причины.

Другой вариант - не приязывать низшее исключение, а логировать. Мотивация - коду не нужно знать, почему именно что-то произошло, а разработчику, который посмотрит в лог - нужно. Аргумент против - пусть вышележащий хэндлер исключения разберется, что с ним делать. Иначе может быть такое, что мы залогировали, а хэндлер разобрался с исключением и в результате у нас в логе ошибка, а проблема решена.

TidyUpBeforeThrowing

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

Причем вот здесь 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

LogAndThrow

При обработке сообщения его можно либо логировать, либо пробрасывать наверх, но никогда не Log And Throw!

Throwing Exception

Никогда не пишите в Java throws Exception.

Throwing the Kitchen Sink

public void foo() throws MyException, AnotherException, SomeOtherException, YetAnotherException {

Бросать несколько checked-исключений можно только если мы знаем, что клиент их будет по разному обрабатывать. Иначе имеет смысл конвертировать их в одно исключение (см. ConvertExceptions)

Log and Return Null

catch (NoSuchMethodException e) { LOG.error("Blah", e); return null; }

Вместо этого нужно пробрасывать (не логируя, см. LogAndThrow) исключение наверх, пусть клиент разберется. null возвращаем в не-исключительном коде.

Throw from Within Finally

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

Multi-line Log Messages

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

Three rules for Effective Exception Handling

https://community.oracle.com/docs/DOC-983219

  1. Be specific
  2. Throw Early - пытаться обнаруживать ошибки и стрелять исключения как можно раньше. Например, проверять входные аргументы на null. Проверять, что файл нормально открылся преждем чем пытаться в него писать. И так далее.
  3. Catch Late - не обрабатывать исключения раньше, чем требуется.

Принцип самурая

https://habr.com/ru/post/128397/

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

Если же данные правильны, то она должна либо выполнить работу, либо умереть (выбросив исключение), но опять же в случае выброса нужно восстановить инварианты класса.

Из принципа следует и то, что нельзя возвращать null или пустую коллекцию при исключениях, потому что так клиент не узнает, что работа не была выполнена. Пусть голова болит у клиента, пробросим исключение ему.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment