Why is Class.newInstance() "evil"?

JavaConstructorRuntimeInstantiation

Java Problem Overview


[Ryan Delucchi][1] asked [here][2] in comment #3 to [Tom Hawtin][3]'s answer:

> why is Class.newInstance() "evil"?

this in response to the code sample:

// Avoid Class.newInstance, for it is evil.
Constructor<? extends Runnable> ctor = runClass.getConstructor();
Runnable doRun = ctor.newInstance();

so, why is it Evil? [1]: https://stackoverflow.com/users/9931/ryan-delucchi [2]: https://stackoverflow.com/questions/194698/how-to-load-a-jar-file-at-runtime#194712 [3]: https://stackoverflow.com/users/4725/tom-hawtin-tackline

Java Solutions


Solution 1 - Java

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 - Java

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 - Java

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAmir AradView Question on Stackoverflow
Solution 1 - JavaChris Jester-YoungView Answer on Stackoverflow
Solution 2 - Javaalexei.vidmichView Answer on Stackoverflow
Solution 3 - JavaEugeneView Answer on Stackoverflow