Ryan Delucchi 質問 here コメント#3で Tom Hawtin の答え:
class.newInstance()が「悪」なのはなぜですか?
これは、コードサンプルへの応答として:
// Avoid Class.newInstance, for it is evil.
Constructor<? extends Runnable> ctor = runClass.getConstructor();
Runnable doRun = ctor.newInstance();
それで、なぜそれが悪なのでしょうか?
Java APIドキュメントはその理由を説明しています( http://Java.Sun.com/javase/6/docs/api/Java/lang/Class.html#newInstance() ):
このメソッドは、チェック済み例外を含む、nullaryコンストラクターによってスローされた例外を伝播することに注意してください。このメソッドを使用すると、コンパイラによって実行されるコンパイル時の例外チェックを効果的にバイパスできます。
Constructor.newInstance
メソッドは、コンストラクターによってスローされた例外を(チェック済み)InvocationTargetException
にラップすることにより、この問題を回避します。
つまり、チェック例外システムを無効にすることができます。
もう一つの理由:
最新のIDEでは、クラスの使用法を見つけることができます。リファクタリング中に、あなたとIDEが変更しようとしているクラスを使用しているコードを知っている場合に役立ちます。
コンストラクターを明示的に使用せず、代わりにClass.newInstance()を使用する場合、リファクタリング中にその使用法が見つからないリスクがあり、コンパイル時にこの問題は現れません。
Constructor::newInstance
たとえば、最終的にClass::newInstance
はJava-9以降廃止されました。
この非常に単純なクラスがあると仮定します(壊れているかどうかは関係ありません):
static class Foo {
public Foo() throws IOException {
throw new IOException();
}
}
そして、リフレクションを介してそのインスタンスを作成しようとします。最初 Class::newInstance
:
Class<Foo> clazz = ...
try {
clazz.newInstance();
} catch (InstantiationException e) {
// handle 1
} catch (IllegalAccessException e) {
// handle 2
}
これを呼び出すと、IOException
がスローされます-問題は、コードがそれを処理せず、handle 1
nor handle 2
はキャッチします。
対照的に、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();
}
そのハンドル3が呼び出されるので、それを処理します。
事実上、Class::newInstance
は例外処理をバイパスします-これは本当に望ましくありません。