Когда правильно для конструктора выдать исключение?

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

См. также: A хороший список лучших практик

Я бы добавил, очень важно, хорошо использовать модификатор final. Использование "окончательной" модификатор, когда это применимо в Java

Сводка:

  1. Используйте модификатор final для обеспечения хорошей инициализации.
  2. Избегайте возврата null в методы, например, при возврате пустых коллекций.
  3. Использовать аннотации @NotNull и @Nullable
  4. Быстрое завершение работы и использование утверждений, чтобы избежать распространения нулевых объектов через все приложение, когда они не должен быть пустым.
  5. Сначала используйте значения с известным объектом: if("knownObject".equals(unknownObject)
  6. Предпочитают valueOf() поверх toString ().
  7. Используйте null safe StringUtils StringUtils.isEmpty(null).

204
задан Don 24 September 2012 в 14:50
поделиться

20 ответов

Задание конструктора должно принести объект в применимое состояние. Существует в основном две философских школы на этом.

Одна группа одобряет двухэтапную конструкцию. Конструктор просто приносит объект в состояние спящего, в котором он отказывается делать любую работу. Существует дополнительная функция, которая делает фактическую инициализацию.

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

Одноэтапные конструкторы должны бросить, если им не удается полностью инициализировать объект. Если объект не может быть инициализирован, нельзя позволить существовать, таким образом, конструктор должен бросить.

266
ответ дан Sebastian Redl 23 November 2019 в 04:54
поделиться

ctors, как предполагается, не делают "умных" вещей, настолько выдающее исключение не нужно так или иначе. Используйте Init () или Установка () метод, если Вы хотите выполнить некоторую установку более сложного объекта.

-2
ответ дан EricSchaefer 23 November 2019 в 04:54
поделиться

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

0
ответ дан Tegan Mulholland 23 November 2019 в 04:54
поделиться

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

http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/chapter_3_section_6.html

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

0
ответ дан Scott Swezey 23 November 2019 в 04:54
поделиться

Мне это - несколько философское проектное решение.

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

Некоторые другие подходы являются init () метод, который идет с некоторыми собственными проблемами. Один из которых удостоверяется, init () на самом деле называют.

вариант А использует ленивый подход для автоматического вызова init () первым разом, когда средство доступа/мутатор называют, но это требует, чтобы любая потенциальная вызывающая сторона должна была волноваться об объекте, являющемся допустимым. (В противоположность "это существует, следовательно это - допустимая философия").

я видел различные предложенные шаблоны разработки, чтобы заниматься этой проблемой также. Такой как способность создать начальный объект через ctor, но имеющий необходимость назвать init () для доставления содержавший, инициализированный объект с accesors/mutators.

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

Приложение

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

0
ответ дан nsanders 23 November 2019 в 04:54
поделиться

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

0
ответ дан scubabbl 23 November 2019 в 04:54
поделиться

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

Это не единственная опция: Это могло закончить конструктора и создать объект, но с методом 'isCoherent ()' возвращение false, чтобы быть в состоянии сигнализировать о несвязном состоянии (который может быть предпочтительным в определенном случае для предотвращения жестокого прерывания рабочего процесса выполнения из-за исключения)
Предупреждение: как сказано EricSchaefer в его комментарии, который может принести некоторую сложность к поблочному тестированию (бросок может увеличиться цикломатическая сложность из функции из-за условия, которое инициировало его)

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

1
ответ дан Community 23 November 2019 в 04:54
поделиться

Я не могу обратиться к лучшей практике в Objective C, но в C++ для конструктора хорошо выдавать исключение. Тем более, что нет никакого другого способа гарантировать, что об исключительном условии, с которым встречаются в конструкции, сообщают, не обращаясь к вызову isOK () метод.

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

1
ответ дан mlbrock 23 November 2019 в 04:54
поделиться

Обычный контракт в OO - то, что методы объекта действительно на самом деле функционируют.

Поэтому как corrolary, чтобы никогда возвратить объект зомби формируют constructor/init.

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

я сначала сделал зомби в Objective C много лет назад.

Как все эмпирические правила, существует "исключение".

совершенно возможно, что определенный интерфейс может иметь контракт, в котором говорится, что там существует, метод "инициализирует", который позволяется thron исключение. То, что объект, реализовывая этот интерфейс не может правильно ответить ни на какие вызовы кроме методов set свойства, пока не инициализируют, назвали. Я использовал это для драйверов устройств в операционной системе OO во время процесса начальной загрузки, и это было осуществимо.

В целом, Вы не хотите объекты зомби. На языках как Smalltalk с [1 110] становятся , вещи становятся немного шипучими шумными, но злоупотребление становится , плохой стиль также. Становятся, позволяет объектному изменению в другой объект на месте, таким образом, нет никакой потребности в обертке конверта (Усовершенствованный C++) или стратегическая модель (GOF).

1
ответ дан Tim Williscroft 23 November 2019 в 04:54
поделиться

Выдача исключения во время конструкции является отличным способом сделать Ваш код путем более сложный. Вещи, которые казались бы простыми внезапно, становятся твердыми. Например, скажем, у Вас есть стек. Как Вы выталкиваете стек и возвращаете главное значение? Ну, если объекты в стеке могут добавить своих конструкторов (создающий временный файл для возврата к вызывающей стороне), Вы не можете гарантировать, что не потеряете данные (декрементный указатель вершины стека, создайте возвращаемое значение с помощью конструктора копии значения в стеке, который бросает, и теперь имейте стек, который просто потерял объект)! Это то, почему станд.:: стек:: поп не возвращает значение, и необходимо назвать станд.:: стек:: вершина.

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

1
ответ дан Don Neufeld 23 November 2019 в 04:54
поделиться

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

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

Эта страница имеет полное обсуждение ситуации в C++.

2
ответ дан Luke Halliwell 23 November 2019 в 04:54
поделиться

Если Вы пишете Средства управления UI (ASPX, WinForms, WPF...) необходимо постараться не выдавать исключения в конструкторе, потому что разработчик (Visual Studio) не может обработать их, когда это создает средства управления. Знайте свой жизненный цикл управления (события управления) и используйте ленивую инициализацию по мере возможности.

3
ответ дан Nick 23 November 2019 в 04:54
поделиться

Посмотрите разделы FAQ C++ 17.2 и 17.4 .

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

3
ответ дан moonshadow 23 November 2019 в 04:54
поделиться

Разумно для конструктора выдать исключение, пока это моется правильно. Если Вы следуете парадигма RAII (Приобретение Ресурса Является Инициализацией), тогда, конструктору довольно свойственно сделать значимую работу; правильно написанный конструктор в свою очередь вымоется после себя, если это не может полностью быть инициализировано.

5
ответ дан Matt Dillard 23 November 2019 в 04:54
поделиться

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

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

4
ответ дан blowdart 23 November 2019 в 04:54
поделиться

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

, Например, если конструктор, как предполагается, выделяет 1 024 КБ поршня, и ему не удается сделать так, он должен выдать исключение, этот способ, которым вызывающая сторона конструктора знает, что объект не готов использоваться и существует ошибка где-нибудь, которая должна быть зафиксирована.

Объекты, которые полуинициализируются и полумертвые проблемы правого дела и проблемы, как там действительно, не являются никаким способом для вызывающей стороны знать. Я сделал бы, чтобы мой конструктор бросил ошибку, когда вещи идут не так, как надо, чем имеющий необходимость полагаться на программирование для выполнения вызова к isOK () функция, которая возвращает TRUE или FALSE.

5
ответ дан Denice 23 November 2019 в 04:54
поделиться

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

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

6
ответ дан Michael L Perry 23 November 2019 в 04:54
поделиться

Существует обычно ничто, чтобы быть полученным путем развода с объектной инициализацией от конструкции. RAII корректен, успешный вызов конструктору должен или привести к полностью инициализированному живому объекту, или это должно перестать работать, и ВЕСЬ , отказы в любой точке в любом пути выполнения кода должны всегда выдавать исключение. Вы ничего не получаете при помощи отдельного init () метод кроме дополнительной сложности на некотором уровне. Контракт ctor должен быть, или это возвращает функциональный доступный объект, или это моется после себя и бросков.

Рассматривают, если Вы реализуете отдельный init метод, все еще необходимо назвать его. Это будет все еще иметь потенциал для выдавания исключения, они все еще должны быть обработаны, и их фактически всегда нужно сразу назвать после конструктора так или иначе, кроме теперь у Вас есть 4 возможных объектных состояния вместо 2 (IE, созданный, инициализированный, неинициализированный, и отказавший по сравнению только с допустимым и не существующим).

В любом случае я натыкался за 25 лет случаев разработки OO, где кажется, что отдельный init метод 'решил бы некоторую проблему', недостатки дизайна. Если Вам не нужен объект ТЕПЕРЬ тогда, Вы не должны создавать его теперь, и если Вам действительно нужен он теперь тогда, Вам нужен в инициализированный. KISS должен всегда быть сопровождаемым принципом, наряду с простым понятием, что поведение, состояние и API любого интерфейса должны отразить то, ЧТО объект делает, не, КАК это делает это, клиентский код даже не должен знать, что объект имеет любой вид внутреннего состояния, которое требует инициализации, таким образом init после того, как шаблон нарушает этот принцип.

31
ответ дан 23 November 2019 в 04:54
поделиться

Eric Lippert говорит существует 4 вида исключений.

  • Критические исключения не являются Вашим отказом, Вы не можете предотвратить их, и Вы не можете разумно вымыться от них.
  • Глупыми исключениями является Ваш собственный проклятый отказ, Вы, возможно, предотвратили их, и поэтому они - ошибки в Вашем коде.
  • Раздражающими исключениями является результат неудачных проектных решений. Раздражающие исключения выдаются при абсолютно неисключительном обстоятельстве, и поэтому должны быть пойманы и обработаны все время.
  • И наконец, внешние исключения, кажется, похожи на несколько раздражающие исключения за исключением того, что они не результат неудачных проектных решений. Скорее они - результат неопрятных внешних фактов, посягающих на Вашу красивую, четкую логику программы.

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

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

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

Наконец, внешних исключений нужно избежать, но если Вы делаете что-то в своем конструкторе, который зависит от внешних обстоятельств (как сетевая или файловая система), было бы уместно выдать исключение.

Ссылка: https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions /

58
ответ дан unional 23 November 2019 в 04:54
поделиться

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

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

2
ответ дан 23 November 2019 в 04:54
поделиться
Другие вопросы по тегам:

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