Czy można zbudować fragment kodu w Javie , który uczyniłby hipotetyczną nie do zdobycia java.lang.ChuckNorrisException
?
Przemyślone myśli wykorzystują na przykład przechwytywacze lub programowanie zorientowane na aspekty .
finalize()
?
Czy można zbudować fragment kodu w Javie , który uczyniłby hipotetyczną nie do zdobycia java.lang.ChuckNorrisException
?
Przemyślone myśli wykorzystują na przykład przechwytywacze lub programowanie zorientowane na aspekty .
finalize()
?
Odpowiedzi:
Nie próbowałem tego, więc nie wiem, czy JVM ograniczyłby coś takiego, ale być może mógłbyś skompilować kod, który rzuca ChuckNorrisException
, ale w czasie wykonywania podaj definicję klasy, ChuckNorrisException
która nie rozszerza Throwable .
AKTUALIZACJA:
To nie działa Generuje błąd weryfikatora:
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.
AKTUALIZACJA 2:
Właściwie możesz to uruchomić, jeśli wyłączysz weryfikator kodu bajtowego! ( -Xverify:none
)
AKTUALIZACJA 3:
Dla tych, którzy przychodzą z domu, oto pełny skrypt:
Utwórz następujące klasy:
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.");
}
}
}
Klasy kompilacji:
javac -cp . TestVillain.java ChuckNorrisException.java
Biegać:
java -cp . TestVillain
Gotcha!
The end.
Skomentuj „przedłuża wyjątek RuntimeException” i rekompiluj ChuckNorrisException.java
tylko :
javac -cp . ChuckNorrisException.java
Biegać:
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.
Uruchom bez weryfikacji:
java -Xverify:none -cp . TestVillain
The end.
Exception in thread "main"
Object
zamiast Throwable
, to? (Kompilator na to nie zezwala, ale skoro już wyłączyliśmy weryfikator, być może można by zhakować kod bajtowy, aby to zrobić.)
Po zastanowieniu się, udało mi się stworzyć wyjątkowy wyjątek. Zdecydowałem się jednak nazwać to JulesWinnfield
, a nie Chuck, ponieważ jest to jeden wyjątek od grzybów-chmur-matek-matek. Co więcej, może nie być to dokładnie to, co miałeś na myśli, ale na pewno nie da się go złapać. Przestrzegać:
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");
}
}
Zrobione! Nieprzechwycony wyjątek.
Wynik:
biegać:
Powiedz co jeszcze raz! Wyzywam cię! Dwukrotnie się odważę!
Wynik Java: 8
BUDOWANIE SUKCESEM (całkowity czas: 0 sekund)
Kiedy będę miał trochę więcej czasu, zobaczę, czy nie mogę wymyślić czegoś innego.
Sprawdź również:
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)
{
}
}
Powoduje przepełnienie stosu - ponownie wyjątki pozostają nieprzechwycone.
JulesWinfield
? Czy system nie zatrzyma się z piskiem, zanim zostanie wyrzucony?
throw new Whatever()
to tak naprawdę dwie części: Whatever it = new Whatever(); throw it;
i system umiera, zanim dotrze do drugiej części.
class cn extends exception{private cn(){}}
Z takim wyjątkiem byłoby oczywiście obowiązkowe użycie System.exit(Integer.MIN_VALUE);
konstruktora, ponieważ tak by się stało, gdybyś rzucił taki wyjątek;)
while(true){}
zamiast System.exit()
.
System.exit()
pracę, instalując menedżera bezpieczeństwa, który go zabrania. zmieniłoby to konstruktor w inny wyjątek (SecurityException), który mógł zostać przechwycony.
Każdy kod może złapać Throwable. Więc nie, jakikolwiek wyjątek, który stworzysz, będzie podklasą Throwable i będzie podlegał złapaniu.
hang
sam spróbowałby złapać
public class ChuckNorrisException extends Exception {
public ChuckNorrisException() {
System.exit(1);
}
}
(To prawda, że technicznie ten wyjątek nigdy nie jest generowany, ale ChuckNorrisException
nie można go wyrzucić - rzuca cię pierwszy).
Każdy rzucony wyjątek musi przedłużać Throwable, aby zawsze można go było złapać. Więc odpowiedź brzmi nie.
Jeśli chcesz, aby to trudne w obsłudze, można przesłonić metody getCause(), getMessage()
, getStackTrace()
, toString()
aby rzucić inny java.lang.ChuckNorrisException
.
catch(Throwable t)
przechowuje go tylko w zmiennej, więc moje sugestie mają zastosowanie tylko w następnym bloku, gdy użytkownik chce poradzić sobie z wyjątkiem
Moja odpowiedź opiera się na pomyśle @ jtahlborn, ale jest to w pełni działający program Java , który można spakować do pliku JAR , a nawet wdrożyć na ulubionym serwerze aplikacji jako część aplikacji internetowej .
Po pierwsze, zdefiniujmy ChuckNorrisException
klasę, aby nie powodowała awarii JVM od samego początku (Chuck naprawdę uwielbia zawieszanie JVM 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);
}
}
Teraz idzie Expendables
klasa, aby go zbudować:
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);
}
}
}
I w końcu Main
klasa skopała tyłek:
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");
}
}
}
Skompiluj i uruchom go za pomocą następującego polecenia:
java -Xverify:none -cp .:<path_to_javassist-3.9.0.GA.jar> chuck.Main
Otrzymasz następujące dane wyjściowe:
before
finally
Nic dziwnego - w końcu to kopnięcie wkoło :)
W konstruktorze możesz uruchomić wątek, który wielokrotnie wywołuje originalThread.stop (ChuckNorisException.this)
Wątek mógł wielokrotnie wychwytywać wyjątek, ale rzucałby go aż do śmierci.
Nie. Wszystkie wyjątki w Javie muszą być podklasowane java.lang.Throwable
i chociaż może to nie być dobrą praktyką, możesz wychwycić każdy typ wyjątku:
try {
//Stuff
} catch ( Throwable T ){
//Doesn't matter what it was, I caught it.
}
Zobacz uzyskać więcej informacji, dokumentację java.lang.Throwable .
Jeśli próbujesz uniknąć zaznaczonych wyjątków ( wyjątków , które muszą być jawnie obsługiwane), możesz podklasę Błąd lub RuntimeException.
W rzeczywistości zaakceptowana odpowiedź nie jest tak ładna, ponieważ Java musi być uruchomiona bez weryfikacji, tzn. Kod nie działałby w normalnych okolicznościach.
AspectJ na ratunek dla prawdziwego rozwiązania !
Klasa wyjątków:
package de.scrum_master.app;
public class ChuckNorrisException extends RuntimeException {
public ChuckNorrisException(String message) {
super(message);
}
}
Aspekt:
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;
}
}
Przykładowa aplikacja:
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!");
}
}
Wynik:
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)
Wariantem tego motywu jest zaskakujący fakt, że można rzucać niezadeklarowane sprawdzone wyjątki od kodu Java. Ponieważ nie jest zadeklarowany w podpisie metod, kompilator nie pozwala na przechwycenie samego wyjątku, chociaż można go przechwycić jako java.lang.Exception.
Oto klasa pomocnicza, która pozwala rzucać wszystko, zadeklarowane lub nie:
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;
}
}
Teraz throw SneakyThrow.sneak(new ChuckNorrisException());
generuje wyjątek ChuckNorrisException, ale kompilator narzeka
try {
throw SneakyThrow.sneak(new ChuckNorrisException());
} catch (ChuckNorrisException e) {
}
o przechwytywaniu wyjątku, który nie jest zgłaszany, jeśli wyjątek ChuckNorrisException jest sprawdzonym wyjątkiem.
Jedynymi ChuckNorrisException
literami w Javie powinny być OutOfMemoryError
i StackOverflowError
.
Możesz faktycznie „złapać” je w sposób, który oznacza catch(OutOfMemoryError ex)
wykona się w przypadku zgłoszenia wyjątku, ale blok ten automatycznie zwróci wyjątek dzwoniącemu.
Nie sądzę, że to wystarcza, public class ChuckNorrisError extends Error
ale możesz spróbować. Nie znalazłem dokumentacji dotyczącej rozszerzeniaError
Is it possible to construct a snippet of code in java that would make a hypothetical java.lang.ChuckNorrisException uncatchable?
Tak, a oto odpowiedź: Zaprojektuj java.lang.ChuckNorrisException
taki, aby nie był to przypadek java.lang.Throwable
. Dlaczego? Obiekt niemożliwy do zdefiniowania jest z definicji nie do złapania, ponieważ nigdy nie można złapać czegoś, czego nigdy nie można wyrzucić.
java.lang.ChuckNorrisException
muszą być wyjątkiem, nie mówiąc już o rzucaniu
Możesz zachować ChuckaNorrisa wewnętrznie lub prywatnie i obudować go lub pochłonąć ...
try { doChuckAction(); } catch(ChuckNorrisException cne) { /*do something else*/ }
Dwa podstawowe problemy z obsługą wyjątków w Javie polegają na tym, że używa on typu wyjątku, aby wskazać, czy należy na nim podjąć działanie, i że zakłada się, że wszystko, co podejmuje działanie w oparciu o wyjątek (tj. „Przechwytuje” to) warunek podstawowy. Przydatne byłoby posiadanie środków, dzięki którym obiekt wyjątku mógłby decydować, które procedury obsługi powinny zostać wykonane i czy procedury obsługi, które do tej pory wykonały, wyczyściły wszystko wystarczająco, aby obecny sposób mógł spełnić warunki wyjścia. Chociaż można tego użyć do stworzenia „niemożliwych do uchwycenia” wyjątków, dwa większe zastosowania to (1) wprowadzenie wyjątków, które będą rozpatrywane tylko wtedy, gdy zostaną przechwycone przez kod, który faktycznie wie, jak sobie z nimi poradzić, i (2) zezwolą do rozsądnego obchodzenia się z wyjątkami, które występują wfinally
FooException
podczas finally
bloku podczas odwijania a BarException
oba wyjątki powinny propagować stos wywołań; oba powinny być możliwe do złapania, ale rozwijanie powinno trwać, dopóki nie zostaną złapane). Niestety nie sądzę, aby istniał jakiś sposób, aby istniejący kod obsługi wyjątków działał w ten sposób bez zepsucia rzeczy.
finally
czyszczenia bloku z wcześniejszego wyjątku, jest całkiem możliwe, że którykolwiek wyjątek, przy braku drugiego, może być czymś, co kod mógłby obsłużyć i kontynuować, ale radzenie sobie z jednym i ignorowanie drugiego byłoby złe. Nie ma jednak mechanizmu generowania złożonego wyjątku, który przetworzyłyby oba programy obsługi.
Foo
może odróżnić wyjątek, który Foo
albo sam się rzucił, albo celowo chce udawać, że sam się rzucił, od tego, któryFoo
nie spodziewał się, że nastąpi wywołanie innej metody. Właśnie tym pojęciem „sprawdzonych” wyjątków powinno być „około”.
Łatwo jest zasymulować niewyłapany wyjątek dla bieżącego wątku. Spowoduje to normalne zachowanie nieprzechwyconego wyjątku, a tym samym wykonanie zadania semantycznie. Niekoniecznie jednak zatrzyma to wykonywanie bieżącego wątku, ponieważ tak naprawdę nie zostanie zgłoszony żaden wyjątek.
Throwable exception = /* ... */;
Thread currentThread = Thread.currentThread();
Thread.UncaughtExceptionHandler uncaughtExceptionHandler =
currentThread.getUncaughtExceptionHandler();
uncaughtExceptionHandler.uncaughtException(currentThread, exception);
// May be reachable, depending on the uncaught exception handler.
Jest to faktycznie przydatne w (bardzo rzadkich) sytuacjach, na przykład gdy Error
wymagana jest poprawna obsługa, ale metoda jest wywoływana z frameworka, który przechwytuje (i odrzuca) dowolne Throwable
.