Вопрос

Java позволяет создавать совершенно новый подтип Throwable, например:

public class FlyingPig extends Throwable { ... }

Теперь, очень редко, Я могу сделать что -то вроде этого:

throw new FlyingPig("Oink!");

И, конечно, в другом месте:

try { ... } catch (FlyingPig porky) { ... }

Мои вопросы:

  • Это плохая идея? А если так, почему?
    • Что можно было сделать, чтобы предотвратить этот подтип, если это плохая идея?
    • Поскольку это не предотвратимо (насколько я знаю), какая катастрофия может привести к?
  • Если это не такая плохая идея, почему бы и нет?
    • Как сделать что -то полезное из того, что вы можете extends Throwable?

Предложенный сценарий № 1

Сценарий, где я был В самом деле Собладает сделать что -то подобное, обладает следующими свойствами:

  • «Событие» - это то, что будем в конце концов. это ожидал. Анкет Это определенно не Error, и ничего нет Exception-Олему о том, когда это происходит.
    • Потому что это ожидал, там будет catch ждет его. Это не будет «проскользнуть» ни на что. Это не «убежит» от какой -либо попытки catch генеральный Exception и/или Error.
  • «Событие» происходит очень редко.
  • Когда это происходит, обычно есть глубокий след.

Так что, возможно, теперь ясно, что я пытаюсь сказать: FlyingPig это результат исчерпывающего рекурсивного поиска.

Существует объект, который необходимо искать: это только вопрос найти его в большом море, которое является пространством поиска. Процесс поиска будет длинным, поэтому относительно дорогая стоимость обработки исключений незначительна. Фактически, традиционная конструкция потока управления альтернативой использования boolean isFound Флаг может быть более дорогим, потому что его необходимо непрерывно проверять на протяжении всего процесса поиска, скорее всего, на каждом уровне рекурсии. Эта проверка потерпит неудачу в 99,99% случаев, но абсолютно необходимо распространять условие завершения. В некотором смысле, пока эффективная, чек неэффективно!

Просто throw-ин FlyingPig Когда найден востребованный объект, вам не нужно загромождать код управлением boolean isFound флаг. Мало того, что в этом отношении не только чистка кода, но и может работать быстрее из -за этого упущения.

Итак, в соответствии с обобщением, выбор между этими двумя:

  • Традиционный подход контроля
    • Использовать boolean isFound, проверяется непрерывно
    • 99,99% случаев, чек - это «трата», потому что это все еще будет false
    • Когда это в конечном итоге становится true, Вы перестаете повторять и должны убедиться, что вы можете правильно расслабиться до первоначального вызова.
  • FlyingPig подход
    • Не беспокойтесь ни с чем boolean isFound.
    • Если найдено, просто throw new FlyingPig(); это ожидал, так что будет catch для этого.
    • Нет управления boolean Флаг, нет потраченного впустую проверку, если вам нужно продолжать идти, бухгалтерия вручную открутить рекурсию и т. Д.

Вопросы:

  • Достоверен ли этот метод (AB) использование исключения? (Есть ли имя для этого?)
  • Если действительно, должно быть FlyingPig extends Throwable, или есть Exception просто хорошо? (Хотя в его обстоятельствах нет ничего исключительного?)
Это было полезно?

Решение

Я бы сказал, что это действительно плохая идея. Много кода реализовано в предположении, что если вы поймаете Error и Exception Вы поймали все возможные исключения. И большинство учебников и учебников скажут вам то же самое. Создав прямой подкласс Throwable Вы потенциально создаете всевозможные проблемы обслуживания и взаимодействия.

Я не могу придумать веской причины расширить Throwable. Анкет Продлевать Exception или RuntimeException вместо.

РЕДАКТИРОВАТЬ - В ответ на предложенный ОП сценарий № 1.

Исключения - очень дорогой способ справиться с «нормальным» контролем потока. В некоторых случаях мы говорим тысячи дополнительных инструкций, выполненных для создания, бросить и поймать исключение. Если вы собираетесь игнорировать общепринятую мудрость и использовать исключения для управления неэффективным потоком, используйте Exception подтип. Попытка притвориться, что что -то - это «событие», а не «исключение», объявляя, как подтип Throwable не собирается ничего достичь.

Тем не менее, ошибочно составить исключение с ошибкой, ошибкой, неправильным, что угодно. И есть Ничего плохого с представлением «исключительного события, которое не является ошибкой, ошибкой, неправильной или чем -то еще» с использованием подкласса Exception. Анкет Ключ в том, что событие должно быть исключительный; т.е. из обычного, происходит очень редко, ...

В итоге, FlyingPig не может быть ошибкой, но это не причина не объявлять его как подтип Exception.

Другие советы

Достоверен ли этот метод (AB) использование исключения? (Есть ли имя для этого?)

На мой взгляд, это не очень хорошая идея:

  • Это нарушает принцип наименьшего удивления, это затрудняет чтение кода, особенно если в этом нет ничего исключительного.
  • Заброшенное исключение - очень дорогая операция в Java (хотя может быть не проблема здесь).

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

Смотрите также:

Если действительно, должно быть FlyingPig расширяется Throwable, или есть Exception просто хорошо? (Хотя в его обстоятельствах нет ничего исключительного?)

Могут быть ситуации, когда вы хотите ловить Throwable не только поймать Exception но и Error Но это редко, люди обычно не ловят Throwable. Анкет Но я не нахожу ситуацию, когда вы хотели бы бросать подкласс Throwable.

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

Итак, чтобы сделать вывод, если вы действительно хотите что -то бросить, бросьте подкласс Exception.

Смотрите также:

Вот пост в блоге от Джона Роуза, архитектора горячей точки:

http://blogs.oracle.com/jrose/entry/longjumps_considered_inexplone

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

Я думаю, что эта техника оправдана, если «скрыта» от клиентов. Т.е. ваш FlyingPig никогда не должен быть в состоянии покинуть вашу библиотеку (все публичные методы должны транзисивно гарантировать не бросать его). Одним из способов гарантировать это было бы сделать это проверенным исключением.

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

А org.junit.Test Аннотация включает в себя None класс, который расширяется Throwable и используется в качестве значения по умолчанию для expected параметр аннотации.

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

Самая большая проблема, о которой я могу придумать, заключается в прагматическом мире, иногда есть оправданные причины, чтобы поймать java.lang.xception. Ваш новый тип броска будет пролететь мимо блоков Try-Catch, которые имели все разумные ожидания подавления (или регистрации, обертывания, что угодно) каждой возможной нерадостной проблемы.

С другой стороны, если вы делаете обслуживание старой системы, которая ООНОправданно подавляя java.lang.xception, вы можете обмануть вокруг него. (Предполагая, что искренняя апелляция о том, чтобы фактически исправить его правильно, отрицается).

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

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

  • Использование наиболее конкретного исключения - отличная идея. Это позволит абоненту обрабатывать различные типы исключений по -разному. Классовая иерархия исключения важна для того, чтобы помнить, поэтому ваше пользовательское исключение должно расширить другой тип броска, который как можно ближе к вашему исключению.
  • Расширение броска может быть слишком высоким уровнем. Попробуйте вместо этого расширить исключение или Runtimeexception (или исключение более низкого уровня, которое ближе к причине, по которой вы бросаете исключение). Имейте в виду разницу между Runtimeexception и исключением.
  • Призыв к методу, который бросает исключение (или подкласс исключения), должен быть заверен в блок Try/Catch, который способен справиться с исключением. Это хорошо для случаев, когда вы ожидаете, что все пойдет не так, из -за обстоятельств, которые могут быть вне вашего контроля (например, сеть снижается).
  • Призыв к методу, который бросает Runtimeexception (или его подклассы), не нужно быть завернутым в блок Try/Catch, который может обрабатывать исключение. (Это, безусловно, может быть, но это не должно быть.) Это больше для исключений, которые действительно не следует ожидать.

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

public class Pig extends Throwable { ... }
public class FlyingPig extends Pig { ... }
public class Swine extends Pig { ... }
public class CustomRuntimeException extends RuntimeException { ... }

И некоторые методы

public void foo() throws Pig { ... }
public void bar() throws FlyingPig, Swine { ... }
// suppose this next method could throw a CustomRuntimeException, but it
// doesn't need to be declared, since CustomRuntimeException is a subclass
// of RuntimeException
public void baz() { ... } 

Теперь у вас может быть какой -то код, который называет эти методы как это:

try {
    foo();
} catch (Pig e) {
    ...
}

try {
    bar();
} catch (Pig e) {
    ...
}

baz();

Обратите внимание, что когда мы звоним bar(), мы можем просто поймать Pig, так как оба FlyingPig и Swine продлевать Pig. Анкет Это полезно, если вы хотите сделать то же самое, чтобы справиться с любым исключением. Вы могли бы, однако, обрабатывать с ними по -другому:

try {
    bar();
} catch (FlyingPig e) {
    ...
} catch (Swine e) {
    ...
}

А Играть! рамки использует что -то подобное для обработки запросов. Обработка запроса проходит много слоев (маршрутизация, промежуточное программное обеспечение, контроллеры, рендеринг шаблонов), а на последнем уровне рендерированный HTML - это завернутый в бросаемый и брошен, который самый верхний слой ловит, разворачивает и отправляет клиенту. Таким образом, ни один из методов во многих участвующих уровнях не должен явно возвращать объект ответа, и при этом им не нужно, чтобы объект ответа был передаваться в качестве аргумента, который будет распространен и изменен.

Я немного отрывочно по деталям. Вы можете просмотреть код игры! структура для деталей.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top