Por que é Class.newInstance () “mal”?
-
10-07-2019 - |
Pergunta
Ryan Delucchi perguntou aqui no comentário # 3 a resposta Tom Hawtin 's:
porque é Class.newInstance () "mal"?
este em resposta à amostra de código:
// Avoid Class.newInstance, for it is evil.
Constructor<? extends Runnable> ctor = runClass.getConstructor();
Runnable doRun = ctor.newInstance();
então, por que é mal?
Solução
A documentação da API Java explica por que ( http://java.sun.com/javase/6/docs/api/java/lang/Class.html#newInstance () ):
Note que este método propaga qualquer exceção lançada pelo construtor nullary, incluindo uma exceção verificada. O uso deste método ignora efetivamente a verificação de exceção em tempo de compilação que seriam realizadas pelo compilador. O método
Constructor.newInstance
evita este problema envolvendo qualquer exceção lançada pelo construtor em umInvocationTargetException
(marcada).
Em outras palavras, ele pode derrotar o sistema de exceções verificadas.
Outras dicas
Mais uma razão:
IDEs modernos permitem que você encontrar usos de classe -. Ajuda durante a refatoração, se você e seu IDE saber o que o código está usando classe que você pretende mudar
Quando você não fizer um uso explícito do construtor, mas o uso Class.newInstance () em vez disso, você corre o risco de não achar que o uso durante a refatoração e este problema não vai se manifestar quando você compilar.
Eu não sei por que ninguém forneceu um exemplo simples baseado explicação para isso, em comparação com Constructor::newInstance
por exemplo, desde finalmente Class::newInstance
foi reprovado desde o java-9.
Suponha que você tenha essa classe muito simples (não importa que ele está quebrado):
static class Foo {
public Foo() throws IOException {
throw new IOException();
}
}
E você tentar criar uma instância dele através de reflexão. Primeiro Class::newInstance
:
Class<Foo> clazz = ...
try {
clazz.newInstance();
} catch (InstantiationException e) {
// handle 1
} catch (IllegalAccessException e) {
// handle 2
}
Chamar isso irá resultar em um IOException
ser jogado -. Problema é que seu código não lidar com isso, nem handle 1
nem handle 2
vai pegá-lo
Em contraste ao fazê-lo através de um 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();
}
que pega 3 será chamado, assim você vai lidar com isso.
Efetivamente, Class::newInstance
ignora o tratamento de exceção -. Que você realmente não quer