java exception in constructor

A constructor is used to initialize an object when it is created. It is syntactically similar to a method. The difference is that the constructors have same name as their class and, have no return type.

There is no need to invoke constructors explicitly these are automatically invoked at the time of instantiation.

Example

Output

Constructor throwing exceptions

Yes, just like methods you can throw exceptions from constructors in. But, if you do so, you need to catch/throw (handle) the exception at the method where you invoke the constructor. If you don’t a compile time error is generated.

Example

In the following example we have a class named Employee whose constructor throws an IOException, we are instantiating this class without handling the exception. Therefore, if you compile this program, it generates a compile time error.

Compile time error

Example

To make this program work properly, wrap the instantiation line within try-catch or, throw the exception.

Are constructors allowed to throw exceptions?

6 Answers 6

Yes, constructors can throw exceptions. Usually this means that the new object is immediately eligible for garbage collection (although it may not be collected for some time, of course). It’s possible for the «half-constructed» object to stick around though, if it’s made itself visible earlier in the constructor (e.g. by assigning a static field, or adding itself to a collection).

One thing to be careful of about throwing exceptions in the constructor: because the caller (usually) will have no way of using the new object, the constructor ought to be careful to avoid acquiring unmanaged resources (file handles etc) and then throwing an exception without releasing them. For example, if the constructor tries to open a FileInputStream and a FileOutputStream , and the first succeeds but the second fails, you should try to close the first stream. This becomes harder if it’s a subclass constructor which throws the exception, of course. it all becomes a bit tricky. It’s not a problem very often, but it’s worth considering.

Yes, they can throw exceptions. If so, they will only be partially initialized and if non-final, subject to attack.

Partially initialized instances of a non-final class can be accessed via a finalizer attack. The attacker overrides the protected finalize method in a subclass, and attempts to create a new instance of that subclass. This attempt fails (in the above example, the SecurityManager check in ClassLoader’s constructor throws a security exception), but the attacker simply ignores any exception and waits for the virtual machine to perform finalization on the partially initialized object. When that occurs the malicious finalize method implementation is invoked, giving the attacker access to this, a reference to the object being finalized. Although the object is only partially initialized, the attacker can still invoke methods on it (thereby circumventing the SecurityManager check).

Хорошо ли сделать конструктор для исключения? Например, у меня есть класс Person , и у меня есть age как его единственный атрибут. Теперь Я предоставляю класс как

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

Однако явно декларирование или метание java.lang.Exception почти всегда плохое.

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

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

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

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

Причиной этого является то, что вы не можете этого сделать:

Вместо этого вы должны сделать это:

В тот момент, когда я создаю SomeObject, я знаю, что это за параметры так почему я должен ожидать, чтобы он обернул его в try catch? Ах, вы говорите, но если я строю объект из динамических параметров, я не знаю, действительны они или нет. Ну, вы можете. проверить параметры перед передачей их конструктору. Это будет хорошей практикой. И если все, что вас беспокоит, является ли параметры действительными, вы можете использовать IllegalArgumentException.

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

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

Но как часто это возможно?

Как упоминалось в другом ответе здесь, в Руководстве 7-3 Java Защищенное кодирование Руководства, бросая исключение в конструкторе не конечного класса, открывает потенциальный вектор атаки:

Руководящий принцип 7-3/ОБЪЕКТ-3: защита от частично инициализированного экземпляры нефинальных классов Когда конструктор в классе без конечных элементов выдает исключение, злоумышленники могут попытаться получить доступ к частичному инициализированные экземпляры этого класса. Обеспечить, чтобы не конечный класс остается полностью непригодным до тех пор, пока его конструктор не завершится успешно.

От JDK 6 до, построение класса подкласса может быть предотвращено путем исключения исключения до завершения конструктора Object. к сделайте это, выполните проверки в выражении, которое оценивается в вызовите этот() или super().

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

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

Доступ к частично инициализированным экземплярам не конечного класса через атаку финализатора. Атакующий переопределяет защищенную финализацию метод в подклассе и пытается создать новый экземпляр этого подкласс. Эта попытка не выполняется (в приведенном выше примере Проверка SecurityManager в конструкторе ClassLoader создает защиту исключение), но злоумышленник просто игнорирует любое исключение и ждет для того, чтобы виртуальная машина выполняла финализацию частично инициализированный объект. Когда это происходит, метод вредоносного завершения вызывается реализация, предоставляющая злоумышленнику доступ к этому, ссылка на завершаемый объект. Хотя объект только частично инициализированный, злоумышленник может все же ссылаться на методы на нем, тем самым обходя проверку SecurityManager. Хотя инициализированный флаг не препятствует доступу к частично инициализированному объекту, он не позволяет методам на этом объекте делать что-либо полезное для взломщик.

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

Более надежный, но и более подробный подход — использовать «указатель на реализация» (или «pimpl» ). Ядро класса перемещается в непубличный класс с вызовами метода пересылки класса интерфейса. Любые попытки использовать класс до его полной инициализации приведут к в исключении NullPointerException. Этот подход также хорош для клонов и десериализации.

Оцените статью