É possível construir um trecho de código em Java que tornaria um hipotético java.lang.ChuckNorrisException
inacessível?
Pensamentos que vieram à mente estão usando, por exemplo, interceptadores ou programação orientada a aspectos .
finalize()
?
É possível construir um trecho de código em Java que tornaria um hipotético java.lang.ChuckNorrisException
inacessível?
Pensamentos que vieram à mente estão usando, por exemplo, interceptadores ou programação orientada a aspectos .
finalize()
?
Respostas:
Eu não tentei isso, então não sei se a JVM restringiria algo assim, mas talvez você possa compilar o código que lança ChuckNorrisException
, mas em tempo de execução forneça uma definição de classe ChuckNorrisException
que não estenda Throwable .
ATUALIZAR:
Isso não funciona. Ele gera um erro de verificação:
Exception in thread "main" java.lang.VerifyError: (class: TestThrow, method: ma\
in signature: ([Ljava/lang/String;)V) Can only throw Throwable objects
Could not find the main class: TestThrow. Program will exit.
ATUALIZAÇÃO 2:
Na verdade, você pode fazer isso funcionar se desativar o verificador de código de bytes! ( -Xverify:none
)
ATUALIZAÇÃO 3:
Para os que seguem de casa, aqui está o script completo:
Crie as seguintes classes:
public class ChuckNorrisException
extends RuntimeException // <- Comment out this line on second compilation
{
public ChuckNorrisException() { }
}
public class TestVillain {
public static void main(String[] args) {
try {
throw new ChuckNorrisException();
}
catch(Throwable t) {
System.out.println("Gotcha!");
}
finally {
System.out.println("The end.");
}
}
}
Classes de compilação:
javac -cp . TestVillain.java ChuckNorrisException.java
Corre:
java -cp . TestVillain
Gotcha!
The end.
O comentário "estende RuntimeException" e recompila ChuckNorrisException.java
apenas :
javac -cp . ChuckNorrisException.java
Corre:
java -cp . TestVillain
Exception in thread "main" java.lang.VerifyError: (class: TestVillain, method: main signature: ([Ljava/lang/String;)V) Can only throw Throwable objects
Could not find the main class: TestVillain. Program will exit.
Executar sem verificação:
java -Xverify:none -cp . TestVillain
The end.
Exception in thread "main"
Object
vez de Throwable
, então? (O compilador não vai permitir isso, mas desde que já tenha desativado o verificador, talvez se poderia cortar o bytecode para fazê-lo.)
Depois de refletir sobre isso, criei com sucesso uma exceção incontornável. Eu escolhi nomeá-lo JulesWinnfield
, no entanto, ao invés de Chuck, porque é uma exceção da mãe que coloca a nuvem em cogumelo. Além disso, pode não ser exatamente o que você tinha em mente, mas certamente não pode ser capturado. Observar:
public static class JulesWinnfield extends Exception
{
JulesWinnfield()
{
System.err.println("Say 'What' again! I dare you! I double dare you!");
System.exit(25-17); // And you shall know I am the LORD
}
}
public static void main(String[] args)
{
try
{
throw new JulesWinnfield();
}
catch(JulesWinnfield jw)
{
System.out.println("There's a word for that Jules - a bum");
}
}
Et voila! Exceção não capturada.
Resultado:
corre:
Diga o que de novo! Atreva-se! Eu duvido você!
Resultado Java: 8
CONSTRUÇÃO BEM SUCEDIDA (tempo total: 0 segundos)
Quando eu tiver um pouco mais de tempo, vou ver se não consigo pensar em outra coisa também.
Além disso, verifique isso:
public static class JulesWinnfield extends Exception
{
JulesWinnfield() throws JulesWinnfield, VincentVega
{
throw new VincentVega();
}
}
public static class VincentVega extends Exception
{
VincentVega() throws JulesWinnfield, VincentVega
{
throw new JulesWinnfield();
}
}
public static void main(String[] args) throws VincentVega
{
try
{
throw new JulesWinnfield();
}
catch(JulesWinnfield jw)
{
}
catch(VincentVega vv)
{
}
}
Causa um estouro de pilha - novamente, as exceções permanecem não detectadas.
JulesWinfield
? O sistema não será interrompido antes de ser lançado?
throw new Whatever()
é realmente duas partes:, Whatever it = new Whatever(); throw it;
e o sistema morre antes de chegar à segunda parte.
class cn extends exception{private cn(){}}
Com essa exceção, seria obviamente obrigatório usar a System.exit(Integer.MIN_VALUE);
partir do construtor, porque é isso que aconteceria se você lançasse uma exceção;)
while(true){}
vez de System.exit()
.
System.exit()
trabalho instalando um gerenciador de segurança que não o permite. isso transformaria o construtor em uma exceção diferente (SecurityException), que poderia ser detectada.
Qualquer código pode pegar Throwable. Portanto, não, qualquer exceção que você criar será uma subclasse de Throwable e estará sujeita a ser capturada.
hang
própria Throwable tentaria capturar ChuckNorrisException: P
public class ChuckNorrisException extends Exception {
public ChuckNorrisException() {
System.exit(1);
}
}
(Concedido, tecnicamente , essa exceção nunca é realmente lançada, mas ChuckNorrisException
não é possível lançar uma adequada - ela lança você primeiro.)
Qualquer exceção que você lançar tem que estender Throwable, para que possa sempre ser capturada. Então a resposta é não.
Se você quiser torná-lo difícil de lidar, você pode substituir métodos getCause(), getMessage()
, getStackTrace()
, toString()
para jogar outro java.lang.ChuckNorrisException
.
catch(Throwable t)
apenas armazena em variável para minhas sugestões se aplicam somente no próximo bloco quando o usuário deseja para lidar com a exceção
Minha resposta é baseada na idéia de @ jtahlborn, mas é um programa Java totalmente funcional , que pode ser empacotado em um arquivo JAR e até implantado no seu servidor de aplicativos favorito como parte de um aplicativo da web .
Antes de tudo, vamos definir a ChuckNorrisException
classe para não travar a JVM desde o início (Chuck realmente ama travar as JVMs BTW :)
package chuck;
import java.io.PrintStream;
import java.io.PrintWriter;
public class ChuckNorrisException extends Exception {
public ChuckNorrisException() {
}
@Override
public Throwable getCause() {
return null;
}
@Override
public String getMessage() {
return toString();
}
@Override
public void printStackTrace(PrintWriter s) {
super.printStackTrace(s);
}
@Override
public void printStackTrace(PrintStream s) {
super.printStackTrace(s);
}
}
Agora vai a Expendables
classe para construí-lo:
package chuck;
import javassist.*;
public class Expendables {
private static Class clz;
public static ChuckNorrisException getChuck() {
try {
if (clz == null) {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("chuck.ChuckNorrisException");
cc.setSuperclass(pool.get("java.lang.Object"));
clz = cc.toClass();
}
return (ChuckNorrisException)clz.newInstance();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
E finalmente a Main
turma para chutar um bumbum:
package chuck;
public class Main {
public void roundhouseKick() throws Exception {
throw Expendables.getChuck();
}
public void foo() {
try {
roundhouseKick();
} catch (Throwable ex) {
System.out.println("Caught " + ex.toString());
}
}
public static void main(String[] args) {
try {
System.out.println("before");
new Main().foo();
System.out.println("after");
} finally {
System.out.println("finally");
}
}
}
Compile e execute-o com o seguinte comando:
java -Xverify:none -cp .:<path_to_javassist-3.9.0.GA.jar> chuck.Main
Você obterá a seguinte saída:
before
finally
Não é surpresa - afinal, é um pontapé redondo :)
No construtor, você pode iniciar um thread que chama repetidamente originalThread.stop (ChuckNorisException.this)
O encadeamento poderia capturar a exceção repetidamente, mas continuaria a lançá-la até morrer.
Não. Todas as exceções em Java devem ser subclasses java.lang.Throwable
e, embora isso não seja uma boa prática, você pode capturar todos os tipos de exceção da seguinte forma:
try {
//Stuff
} catch ( Throwable T ){
//Doesn't matter what it was, I caught it.
}
Consulte a documentação java.lang.Throwable para obter mais informações.
Se você estiver tentando evitar exceções verificadas (aquelas que devem ser tratadas explicitamente), convém subclassificar Error ou RuntimeException.
Na verdade, a resposta aceita não é tão boa porque o Java precisa ser executado sem verificação, ou seja, o código não funcionaria em circunstâncias normais.
AspectJ para o resgate da solução real !
Classe de exceção:
package de.scrum_master.app;
public class ChuckNorrisException extends RuntimeException {
public ChuckNorrisException(String message) {
super(message);
}
}
Aspecto:
package de.scrum_master.aspect;
import de.scrum_master.app.ChuckNorrisException;
public aspect ChuckNorrisAspect {
before(ChuckNorrisException chuck) : handler(*) && args(chuck) {
System.out.println("Somebody is trying to catch Chuck Norris - LOL!");
throw chuck;
}
}
Aplicação de exemplo:
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
catchAllMethod();
}
private static void catchAllMethod() {
try {
exceptionThrowingMethod();
}
catch (Throwable t) {
System.out.println("Gotcha, " + t.getClass().getSimpleName() + "!");
}
}
private static void exceptionThrowingMethod() {
throw new ChuckNorrisException("Catch me if you can!");
}
}
Resultado:
Somebody is trying to catch Chuck Norris - LOL!
Exception in thread "main" de.scrum_master.app.ChuckNorrisException: Catch me if you can!
at de.scrum_master.app.Application.exceptionThrowingMethod(Application.java:18)
at de.scrum_master.app.Application.catchAllMethod(Application.java:10)
at de.scrum_master.app.Application.main(Application.java:5)
Uma variante do tema é o fato surpreendente de que você pode lançar exceções verificadas não declaradas do código Java. Como não está declarado na assinatura dos métodos, o compilador não permitirá que você capture a exceção em si, mas pode capturá-la como java.lang.Exception.
Aqui está uma classe auxiliar que permite lançar qualquer coisa, declarada ou não:
public class SneakyThrow {
public static RuntimeException sneak(Throwable t) {
throw SneakyThrow.<RuntimeException> throwGivenThrowable(t);
}
private static <T extends Throwable> RuntimeException throwGivenThrowable(Throwable t) throws T {
throw (T) t;
}
}
Agora throw SneakyThrow.sneak(new ChuckNorrisException());
lança um ChuckNorrisException, mas o compilador reclama
try {
throw SneakyThrow.sneak(new ChuckNorrisException());
} catch (ChuckNorrisException e) {
}
sobre como capturar uma exceção que não é lançada se ChuckNorrisException for uma exceção verificada.
Os únicos ChuckNorrisException
s em Java devem ser OutOfMemoryError
e StackOverflowError
.
Você pode realmente "capturá-los" da maneira que um catch(OutOfMemoryError ex)
será executado caso a exceção seja lançada, mas esse bloco retrocederá automaticamente a exceção para o chamador.
Eu não acho que public class ChuckNorrisError extends Error
isso funcione, mas você pode tentar. Não encontrei nenhuma documentação sobre a extensãoError
Is it possible to construct a snippet of code in java that would make a hypothetical java.lang.ChuckNorrisException uncatchable?
Sim, e aqui está a resposta: Crie o seu de java.lang.ChuckNorrisException
forma que não seja uma instância do java.lang.Throwable
. Por quê? Um objeto que não pode ser jogado é inacessível por definição, porque você nunca pode capturar algo que nunca pode ser lançado.
java.lang.ChuckNorrisException
devem ser uma exceção, muito menos jogáveis #
Você pode manter ChuckNorris interno ou privado e encapsulá-lo ou segui-lo ...
try { doChuckAction(); } catch(ChuckNorrisException cne) { /*do something else*/ }
Dois problemas fundamentais com o tratamento de exceções em Java são que ele usa o tipo de exceção para indicar se uma ação deve ser executada com base nela e que qualquer coisa que execute uma ação com base em uma exceção (por exemplo, "pega") é considerada como resolvida a condição subjacente. Seria útil ter um meio pelo qual um objeto de exceção pudesse decidir quais manipuladores devem ser executados e se os manipuladores que executaram até agora limparam as coisas o suficiente para que o presente método satisfaça suas condições de saída. Embora isso possa ser usado para tornar exceções "inatacáveis", dois usos maiores seriam (1) criar exceções que só serão consideradas manipuladas quando forem capturadas pelo código que realmente sabe lidar com elas,finally
FooException
durante um finally
bloco durante o desenrolamento de a BarException
, ambas as exceções devem propagar a pilha de chamadas; ambos devem ser capturáveis, mas o desenrolamento deve continuar até que ambos sejam capturados). Infelizmente, acho que não haveria maneira de fazer com que o código de tratamento de exceções existente funcionasse dessa maneira sem interromper as coisas.
finally
bloco está limpando de uma exceção anterior, é bem possível que uma exceção, na ausência da outra, possa ser algo com o qual se espera que o código manipule e continue, mas lidar com um e ignorar o outro seria ruim. Porém, não há mecanismo para produzir uma exceção composta que ambos os manipuladores processariam.
Foo
podem distinguir entre uma exceção que Foo
se lançou ou deliberadamente quer fingir que se lançou, de uma que Foo
não esperava que acontecesse quando foi chamando algum outro método. É sobre isso que a noção de exceções "verificadas" deve ser "sobre".
É facilmente possível simular uma exceção não capturada no encadeamento atual. Isso acionará o comportamento regular de uma exceção não capturada e, portanto, executará o trabalho semanticamente. No entanto, não necessariamente interromperá a execução do encadeamento atual, pois nenhuma exceção é realmente lançada.
Throwable exception = /* ... */;
Thread currentThread = Thread.currentThread();
Thread.UncaughtExceptionHandler uncaughtExceptionHandler =
currentThread.getUncaughtExceptionHandler();
uncaughtExceptionHandler.uncaughtException(currentThread, exception);
// May be reachable, depending on the uncaught exception handler.
Isso é realmente útil em situações (muito raras), por exemplo, quando o Error
manuseio adequado é necessário, mas o método é chamado a partir de uma estrutura que captura (e descarta) qualquerThrowable
.