Почему бы не использовать исключения в качестве регулярного потока управления?

Вы можете использовать barryvdh / laravel-debugbar, вы найдете все ответы, которые вам нужны.

184
задан Peter 17 July 2015 в 07:38
поделиться

19 ответов

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

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

Пример: Microsoft Volta проект, позволяющий писать веб-приложения в прямом .NET, и пусть фреймворк позаботится о том, чтобы выяснить, какие биты должны выполняться и куда Одним из следствий этого является то, что Volta должна иметь возможность компилировать CIL в JavaScript, чтобы вы могли запускать код на клиенте. Однако есть проблема: .NET имеет многопоточность, а JavaScript - нет. Итак, Volta реализует продолжения в JavaScript, используя исключения JavaScript, а затем реализует потоки .NET, используя эти продолжения. Таким образом, приложения Volta, использующие потоки, могут быть скомпилированы для запуска в неизмененном браузере - Silverlight не требуется.

затем реализует потоки .NET, используя эти продолжения. Таким образом, приложения Volta, использующие потоки, могут быть скомпилированы для запуска в неизмененном браузере - Silverlight не требуется.

затем реализует потоки .NET, используя эти продолжения. Таким образом, приложения Volta, использующие потоки, могут быть скомпилированы для запуска в неизмененном браузере - Silverlight не требуется.

2
ответ дан Jörg W Mittag 23 November 2019 в 05:55
поделиться

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

В JVM создание исключения не так дорого, только создание исключения с новым xyzException (...), потому что последнее включает в себя стековую прогулку. Так что, если у вас есть некоторые исключения, созданные заранее, Вы можете бросить их много раз без затрат. Конечно, таким образом вы не можете передавать данные вместе с исключением, но я думаю, что это все равно плохо.

1
ответ дан Ingo 23 November 2019 в 05:55
поделиться

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

1
ответ дан Mesh 23 November 2019 в 05:55
поделиться

Typically there is nothing wrong, per se, with handling an exception at a low level. An exception IS a valid message that provides a lot of detail for why an operation cannot be performed. And if you can handle it, you ought to.

In general if you know there is a high probability of failure that you can check for... you should do the check... i.e. if(obj != null) obj.method()

In your case, i'm not familiar enough with the C# library to know if date time has an easy way to check whether a timestamp is out of bounds. If it does, just call if(.isvalid(ts)) в противном случае ваш код в основном хорош.

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

2
ответ дан 23 November 2019 в 05:55
поделиться

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

Используя возвращаемые значения, чтобы сигнализировать об ошибке проверки, все просто: если метод вернул число, меньшее 0, произошла ошибка. Как тогда сказать , какой параметр не прошел проверку?

Я помню, что из моих дней C многие функции возвращали коды ошибок, например:

-1 - x lesser then MinX
-2 - x greater then MaxX
-3 - y lesser then MinY

и т. Д.

Действительно ли он менее читабелен, чем создание и перехват исключения?

3
ответ дан kender 23 November 2019 в 05:55
поделиться

Поскольку код трудно читать, у вас могут возникнуть проблемы с его отладкой, вы будете вносить новые ошибки при исправлении ошибок после долгое время, это дороже с точки зрения ресурсов и времени, и это раздражает вас, если вы отлаживаете свой код, и отладчик останавливается при возникновении каждого исключения;)

4
ответ дан Gambrinus 23 November 2019 в 05:55
поделиться

Я не очень понимаю, как вы управляете потоком программ в приведенном вами коде. Вы никогда не увидите другого исключения, кроме исключения ArgumentOutOfRange. (Таким образом, ваше второе предложение поймать никогда не будет выполнено). Все, что вы делаете, это используете чрезвычайно дорогой бросок, чтобы имитировать оператор if.

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

5
ответ дан Jason Punyon 23 November 2019 в 05:55
поделиться

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

Лучший способ сократить затраты на создание исключений - это переопределите метод fillInStackTrace () следующим образом:

public Throwable fillInStackTrace() { return this; }

В таком исключении не будут заполнены трассировки стека.

7
ответ дан paweloque 23 November 2019 в 05:55
поделиться

How about performance? While load testing a .NET web app we topped out at 100 simulated users per web server until we fixed a commonly-occuring exception and that number increased to 500 users.

9
ответ дан James Koch 23 November 2019 в 05:55
поделиться

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

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

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

11
ответ дан mouviciel 23 November 2019 в 05:55
поделиться

Первая реакция на множество ответов:

вы пишете для программистов и принцип наименьшего удивление

Конечно! Но если просто не все яснее все время.

Это не должно быть удивительно , например: catch (1 / x) catch (DivisionByZero) более понятен, чем любой, если мне (в Конраде другие). Тот факт, что такого рода программирование не ожидается, является чисто условным и действительно актуальным. Может быть, в моем примере, если было бы яснее.

Но DivisionByZero и FileNotFound в этом отношении более понятны, чем ifs.

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

Что касается принципа наименьшего удивления: Опасность круговых рассуждений здесь: предположим, что целое сообщество использует плохой дизайн, этот дизайн станет ожидаемым! Поэтому этот принцип не может быть граалом и должен быть тщательно продуман.

исключения для обычных ситуаций, как вы находите необычные (то есть исключительные) ситуации?

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

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

Поэтому этот принцип не может быть граалом и должен быть тщательно продуман.

исключения для обычных ситуаций, как вы находите необычные (то есть исключительные) ситуации?

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

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

Поэтому этот принцип не может быть граалом и должен быть тщательно продуман.

исключения для обычных ситуаций, как вы находите необычные (то есть исключительные) ситуации?

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

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

я не должен признать этот вопрос.

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

я не должен признать этот вопрос.

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

24
ответ дан Peter 23 November 2019 в 05:55
поделиться

Возможно, вам будет интересно взглянуть на систему условий Common Lisp, которая является своего рода обобщением исключений сделано правильно. Поскольку вы можете разматывать стек или не контролируемым образом, вы также получаете «перезапуск», что очень удобно.

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

2
ответ дан simon 23 November 2019 в 05:55
поделиться

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

Например, когда я пытаюсь отследить ошибку в VS, я обычно включаю «разбить на все исключения». Если вы используете исключения для управления потоком, то я буду регулярно ломать отладчик и буду вынужден игнорировать эти неисключительные исключения, пока не доберусь до реальной проблемы. Это может свести кого-то с ума !!

4
ответ дан Sean 23 November 2019 в 05:55
поделиться

Если вы используете обработчики исключений для потока управления, вы слишком общий и ленивый. Как уже упоминалось, вы знаете, что что-то случилось, если вы обрабатываете обработку в обработчике, но что именно? По сути, вы используете исключение для оператора else, если вы используете его для потока управления.

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

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

Если вы добавите логику в обработчик исключений, чтобы определить, что именно произошло, то вы были бы весьма глупы, если бы не помещали эту логику в блок try.

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

Наконец, все предварительные проверки показывают, что вы знаете или ожидаете, произойдут и делают это явным. Код должен быть понятен в намерениях. Что бы вы предпочли прочитать?

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

Если вы добавите логику в свой обработчик исключений, чтобы определить, что именно произошло, то вы быть довольно глупым, чтобы не помещать эту логику в блок try.

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

Наконец, все предварительные проверки показывают, что вы знаете или ожидаете, произойдут и делают это явным. Код должен быть понятен в намерениях. Что бы вы предпочли прочитать?

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

Если вы добавите логику в свой обработчик исключений, чтобы определить, что именно произошло, то вы быть довольно глупым, чтобы не помещать эту логику в блок try.

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

Наконец, все предварительные проверки показывают, что вы знаете или ожидаете, произойдут и делают это явным. Код должен быть понятен в намерениях. Что бы вы предпочли прочитать?

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

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

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

Наконец, все предварительные проверки показывают, что вы знаете или ожидаете, произойдут и делают это явным. Код должен быть понятен в намерениях. Что бы вы предпочли прочитать?

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

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

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

Наконец, все предварительные проверки показывают, что вы знаете или ожидаете, произойдут и делают это явным. Код должен быть понятен в намерениях. Что бы вы предпочли прочитать?

тогда вы были бы довольно глупы, если бы не помещали эту логику в блок try.

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

Наконец, все предварительные проверки показывают, что вы знаете или ожидаете, произойдут и делают это явным. Код должен быть понятен в намерениях. Что бы вы предпочли прочитать?

тогда вы были бы довольно глупы, если бы не помещали эту логику в блок try.

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

Наконец, все предварительные проверки показывают, что вы знаете или ожидаете, произойдут и делают это явным. Код должен быть понятен в намерениях. Что бы вы предпочли прочитать?

Наконец, все предварительные проверки показывают, что вы знаете или ожидаете, произойдут и делают это явным. Код должен быть понятен в намерениях. Что бы вы предпочли прочитать?

Наконец, все предварительные проверки показывают, что вы знаете или ожидаете, произойдут и делают это явным. Код должен быть понятен в намерениях. Что бы вы предпочли прочитать?

2
ответ дан 23 November 2019 в 05:55
поделиться

Джош Блох активно занимается этой темой в Effective Java. Его предложения освещают и должны относиться и к .Net (за исключением деталей).

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

Например, второй метод проще в использовании, чем первый:

/**
 * Adds two positive numbers.
 *
 * @param addend1 greater than zero
 * @param addend2 greater than zero
 * @throws AdditionException if addend1 or addend2 is less than or equal to zero
 */
int addPositiveNumbers(int addend1, int addend2) throws AdditionException{
  if( addend1 <= 0 ){
     throw new AdditionException("addend1 is <= 0");
  }
  else if( addend2 <= 0 ){
     throw new AdditionException("addend2 is <= 0");
  }
  return addend1 + addend2;
}

/**
 * Adds two positive numbers.
 *
 * @param addend1 greater than zero
 * @param addend2 greater than zero
 */
public int addPositiveNumbers(int addend1, int addend2) {
  if( addend1 <= 0 ){
     throw new IllegalArgumentException("addend1 is <= 0");
  }
  else if( addend2 <= 0 ){
     throw new IllegalArgumentException("addend2 is <= 0");
  }
  return addend1 + addend2;
}

В любом случае вам нужно проверить, чтобы убедиться, что вызывающая сторона использует ваш API надлежащим образом. Но во втором случае вам это требуется (неявно). Мягкие исключения по-прежнему будут выдаваться, если пользователь не прочитал Javadoc, но:

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

С точки зрения уровня земли, исключения не следует использовать в качестве кодов возврата, в основном потому, что вы усложнил не только ВАШ API, но и API вызывающего.

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

8
ответ дан Carl Manaster 23 November 2019 в 05:55
поделиться

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

I have.

Программа была довольно сложной (это был сервер распределенных вычислений), и небольшая модификация на одной стороне программы могла легко сломать что-то в совершенно другом месте.

Хотелось бы просто запустить запрограммируйте и подождите, пока возникнут исключения, но при запуске было около 200 исключений при нормальном ходе операций

Моя точка зрения: если вы используете исключения для обычных ситуаций, как вы находите необычные (т. е. исключений al) ситуаций?

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

162
ответ дан 23 November 2019 в 05:55
поделиться

Мое эмпирическое правило:

  • Если вы можете сделать что-нибудь для восстановления после ошибки, поймайте исключения
  • ] Если ошибка является очень распространенной (например, пользователь попытался войти в систему с неверным паролем), используйте returnvalues ​​
  • Если вы не можете ничего сделать, чтобы исправить ошибку, оставьте ее необработанной (или перехватите ее в своем main-catcher, чтобы выполнить некоторое изящное завершение приложения)

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

Возьмите этот пример:

try
{
   DoSomeMethod();  //Can throw Exception1
   DoSomeOtherMethod();  //Can throw Exception1 and Exception2
}
catch(Exception1)
{
   //Okay something messed up, but is it SomeMethod or SomeOtherMethod?
}

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

Class1 myInstance;
try
{
   myInstance = Class1Factory.Build();
}
catch(SomeException)
{
   // Couldn't instantiate class, do something else..
}
myInstance.BestMethodEver();   // Will throw a compile-time error, saying that myInstance is uninitalized, which it potentially is.. :(

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

26
ответ дан 23 November 2019 в 05:55
поделиться

Исключения в основном являются нелокальными goto утверждениями со всеми последствиями последнего. Использование исключений для управления потоком нарушает принцип наименьшего удивления , затрудняет чтение программ (помните, что программы пишутся в первую очередь для программистов).

Более того, этого не ожидают производители компиляторов. Они ожидают, что исключения будут создаваться редко, и они обычно делают код throw довольно неэффективным. Создание исключений является одной из самых дорогих операций в .NET.

Однако некоторые языки (особенно Python) используют исключения в качестве конструкций управления потоком. Например, итераторы вызывают исключение StopIteration , если больше нет элементов. Даже стандартные языковые конструкции (такие как для ) полагаются на это.

152
ответ дан 23 November 2019 в 05:55
поделиться

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

Если вы используете функцию непреднамеренно, но не хотите использовать функцию, разработанную для этой цели, будет сопутствующая стоимость. В этом случае страдают ясность и производительность без реальной добавленной стоимости. Что дает вам использование исключений по сравнению с широко распространенным утверждением if ?

Другими словами: просто потому, что вы можете , не означает, что вы должны .

3
ответ дан 23 November 2019 в 05:55
поделиться
Другие вопросы по тегам:

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