Why is Class.newInstance() "evil"?
Solution 1:
The Java API documentation explains why (http://java.sun.com/javase/6/docs/api/java/lang/Class.html#newInstance()):
Note that this method propagates any exception thrown by the nullary constructor, including a checked exception. Use of this method effectively bypasses the compile-time exception checking that would otherwise be performed by the compiler. The
Constructor.newInstance
method avoids this problem by wrapping any exception thrown by the constructor in a (checked)InvocationTargetException
.
In other words, it can defeat the checked exceptions system.
Solution 2:
One more reason:
Modern IDEs allow you to find class usages - it helps during refactoring, if you and your IDE know what code is using class that you plan to change.
When you don't do an explicit usage of the constructor, but use Class.newInstance() instead, you risk not to find that usage during refactoring and this problem will not manifest itself when you compile.
Solution 3:
I don't know why no one provided a simple example based explanation to this, as compared to Constructor::newInstance
for example, since finally Class::newInstance
was deprecated since java-9.
Suppose you have this very simple class (does not matter that it is broken):
static class Foo {
public Foo() throws IOException {
throw new IOException();
}
}
And you try to create an instance of it via reflection. First Class::newInstance
:
Class<Foo> clazz = ...
try {
clazz.newInstance();
} catch (InstantiationException e) {
// handle 1
} catch (IllegalAccessException e) {
// handle 2
}
Calling this will result in a IOException
being thrown - problem is that your code does not handle it, neither handle 1
nor handle 2
will catch it.
In contrast when doing it via a Constructor
:
Constructor<Foo> constructor = null;
try {
constructor = clazz.getConstructor();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
Foo foo = constructor.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
System.out.println("handle 3 called");
e.printStackTrace();
}
that handle 3 will be called, thus you will handle it.
Effectively, Class::newInstance
bypasses the exception handling - which you really don't want.