Чи можливо побудувати фрагмент коду на Java, який зробив би гіпотетичним java.lang.ChuckNorrisExceptionнерозбірливим?
Думки, які прийшли вам на думку, використовують, наприклад, перехоплювачі або орієнтоване на аспекти програмування .
finalize()?
Чи можливо побудувати фрагмент коду на Java, який зробив би гіпотетичним java.lang.ChuckNorrisExceptionнерозбірливим?
Думки, які прийшли вам на думку, використовують, наприклад, перехоплювачі або орієнтоване на аспекти програмування .
finalize()?
Відповіді:
Я не пробував цього, тому не знаю, чи обмежив би JVM щось подібне, але, можливо, ви могли б скласти код, який кидає ChuckNorrisException, але під час виконання надати визначення класу, ChuckNorrisExceptionяке не поширює Throwable .
ОНОВЛЕННЯ:
Це не працює. Він генерує помилку верифікатора:
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.
ОНОВЛЕННЯ 2:
Насправді ви можете змусити це працювати, якщо вимкнути перевірку байтового коду! ( -Xverify:none)
ОНОВЛЕННЯ 3:
Для тих, хто йде з дому, ось повний сценарій:
Створіть такі класи:
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.");
}
}
}
Компілюйте класи:
javac -cp . TestVillain.java ChuckNorrisException.java
Виконати:
java -cp . TestVillain
Gotcha!
The end.
Прокоментуйте "розширює RuntimeException" і перекомпілюйте ChuckNorrisException.javaлише :
javac -cp . ChuckNorrisException.java
Виконати:
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.
Запустити без перевірки:
java -Xverify:none -cp . TestVillain
The end.
Exception in thread "main"
Objectзамість Throwableцього? (Компілятор не дозволить цього, але оскільки ми вже відключили перевіряючий, можливо, хтось може зламати байт-код, щоб це зробити.)
Поміркувавши це, я успішно створив невловимий виняток. Я вирішив назвати це JulesWinnfield, проте, а не Чак, тому що це один виняток гриби-хмари, що лежить мама. Крім того, це може бути не саме те, що ви мали на увазі, але це, безумовно, не може бути спіймане. Дотримуйтесь:
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! Неперехоплене виключення.
Вихід:
запустити:
Скажи знову "Що"! Я смію тебе! Я подвійно наважуюся на тебе!
Результат Java: 8
БУДІВ УСПІШНО (загальний час: 0 секунд)
Коли у мене ще трохи часу, я побачу, чи не можу я придумати ще щось.
Також перевірте це:
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)
{
}
}
Викликає переповнення стека - знову ж таки, винятки залишаються незрозумілими.
JulesWinfield? Невже система не зупиниться перед викидом?
throw new Whatever()справді складається з двох частин: Whatever it = new Whatever(); throw it;і система вмирає, перш ніж вона досягне другої частини.
class cn extends exception{private cn(){}}
За таким винятком, очевидно, було б обов'язково використовувати a System.exit(Integer.MIN_VALUE);від конструктора, тому що це станеться, якщо ви викинете такий виняток;)
while(true){}замість System.exit().
System.exit()роботі, встановивши менеджер безпеки, який забороняє його працювати. це перетворило б конструктор на інший виняток (SecurityException), який може бути спійманий.
Будь-який код може зловити Throwable. Тож ні, незалежно від того, який ви створюєте виняток, буде підкласом Throwable, і він буде підлягати спійманню.
hangсама б у спробі зловити ChuckNorrisException: P
public class ChuckNorrisException extends Exception {
public ChuckNorrisException() {
System.exit(1);
}
}
(Звичайно, технічно цей виняток ніколи насправді не кидається, але власне ChuckNorrisExceptionне можна кидати - він кидає вас першим.)
Будь-який виняток, який ви кинете, повинен поширювати Throwable, тому його завжди можна зловити. Тож відповідь - ні.
Якщо ви хочете ускладнити обробку, ви можете замінити методи getCause(), getMessage() , getStackTrace(), toString()щоб кинути інші java.lang.ChuckNorrisException.
catch(Throwable t)зберігає його лише в змінній, тому мої пропозиції застосовуються лише в наступному блоці, коли користувач хоче впоратися з винятком
Моя відповідь заснована на ідеї @ jtahlborn, але це повністю працююча програма Java , яку можна упакувати у файл JAR і навіть розгорнути на ваш улюблений сервер додатків у складі веб-програми .
Перш за все, давайте визначимо ChuckNorrisExceptionклас, щоб він не збивав JVM з самого початку (Чак дуже любить збій 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);
}
}
Тепер іде Expendablesклас для його побудови:
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);
}
}
}
І, нарешті, Mainклас поштовх прикладом:
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");
}
}
}
Складіть і запустіть його за допомогою наступної команди:
java -Xverify:none -cp .:<path_to_javassist-3.9.0.GA.jar> chuck.Main
Ви отримаєте наступний вихід:
before
finally
Не дивно - адже це кінець круглим будинком :)
У конструкторі ви можете запустити потік, який неодноразово викликає originalThread.stop (ChuckNorisException.this)
Нитка може виловлювати виняток неодноразово, але продовжуватиме її кидати, поки вона не відмирає.
Ні. Усі винятки в Java повинні містити підклас java.lang.Throwable, і хоча це може бути недоброю практикою, ви можете вловлювати кожен тип винятку, як наприклад:
try {
//Stuff
} catch ( Throwable T ){
//Doesn't matter what it was, I caught it.
}
Дивіться java.lang.Throwable документації .
Якщо ви намагаєтеся уникати перевірених винятків (тих, які повинні бути явно оброблені), тоді вам потрібно буде підклас Помилка або RuntimeException.
Насправді прийнята відповідь не така приємна, тому що Java потрібно запускати без перевірки, тобто код не працює в звичайних обставинах.
Аспект J на допомогу для реального рішення !
Клас винятку:
package de.scrum_master.app;
public class ChuckNorrisException extends RuntimeException {
public ChuckNorrisException(String message) {
super(message);
}
}
Аспект:
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;
}
}
Зразок застосування:
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!");
}
}
Вихід:
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)
Варіантом теми є дивовижний факт, що ви можете викидати незадекларовані перевірені винятки з коду Java. Оскільки це не задекларовано в підписі методів, компілятор не дозволить вам зловити виняток, хоча ви можете впізнати його як java.lang.Exception.
Ось клас помічників, який дозволяє кидати що-небудь, заявлене чи ні:
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;
}
}
Тепер throw SneakyThrow.sneak(new ChuckNorrisException());кидає ChuckNorrisException, але компілятор скаржиться на
try {
throw SneakyThrow.sneak(new ChuckNorrisException());
} catch (ChuckNorrisException e) {
}
про вилучення виключення, яке не викидається, якщо ChuckNorrisException є перевіреним винятком.
Єдиним ChuckNorrisExceptions на Java повинен бути OutOfMemoryErrorі StackOverflowError.
Ви насправді можете «зловити» їх засобами, які а catch(OutOfMemoryError ex) виконують у випадку, якщо виняток буде кинуто, але цей блок автоматично повторно скине виняток для абонента.
Я не думаю, що public class ChuckNorrisError extends Errorце робить трюк, але ви можете спробувати. Я не знайшов жодної документації про продовженняError
Is it possible to construct a snippet of code in java that would make a hypothetical java.lang.ChuckNorrisException uncatchable?
Так, і ось відповідь: Створіть java.lang.ChuckNorrisExceptionтак, щоб він не був екземпляром java.lang.Throwable. Чому? Об'єкт, який не можна захистити, за визначенням неможливий для неможливості, тому що ніколи не можна зловити те, що ніколи не можна кинути.
java.lang.ChuckNorrisExceptionповинні бути винятком, не кажучи вже про перекидання
Ви можете тримати ЧакНорріса внутрішнім або приватним і інкапсулювати його або набрякати ...
try { doChuckAction(); } catch(ChuckNorrisException cne) { /*do something else*/ }
Дві основні проблеми, пов’язані з обробкою винятків у Java, полягають у тому, що він використовує тип винятку для вказівки, чи слід вживати дії на його основі, і що припускається вирішити все, що вживає дій, заснованих на винятку (тобто "зловити його"). основна умова. Було б корисно мати засоби, за допомогою яких об'єкт виключення міг би вирішити, які обробники повинні виконуватись, і чи обробники, які виконали до цього часу, очистили речі достатньо, щоб даний метод задовольнив його умови виходу. Хоча це може використовуватися для винятку "нерозбірливих" винятків, двома більшими можливостями було б (1) робити винятки, які будуть вважатися обробленими лише тоді, коли вони будуть спіймані за кодом, який насправді знає, як з ними боротися,finallyFooExceptionпід часfinallyблок під час розмотування a BarException, обидва винятки повинні поширювати стек виклику; обидва повинні підлягати виловленню, але розмотування слід продовжувати до тих пір, поки обидва не потраплять). На жаль, я не думаю, що не було б ніякого способу змусити існуючий код обробки обставин таким чином працювати, не порушуючи речі.
finallyочищення блоку від попереднього винятку, цілком можливо, що будь-який виняток, за відсутності іншого, може бути чимось, з яким кодом можна було б обробляти і продовжувати, але поводження з одним і ігнорування іншого було б погано. Однак немає механізму, щоб створити складене виключення, яке обробляли б обидва обробники.
Fooможе відрізняти виняток, який Fooабо кинув себе, або навмисно хоче зробити вигляд, що кинув себе, від того, якого Fooне очікував, що станеться, коли він виклик якогось іншого методу. Ось яким має бути поняття "перевірені" винятки "про".
Легко можна симулювати невиконаний виняток у поточній нитці. Це призведе до регулярної поведінки неприхованого винятку, і, таким чином, робота буде виконана семантично. Однак це не обов'язково зупинить виконання поточного потоку, оскільки насправді не виняток.
Throwable exception = /* ... */;
Thread currentThread = Thread.currentThread();
Thread.UncaughtExceptionHandler uncaughtExceptionHandler =
currentThread.getUncaughtExceptionHandler();
uncaughtExceptionHandler.uncaughtException(currentThread, exception);
// May be reachable, depending on the uncaught exception handler.
Це насправді корисно в (дуже рідкісних) ситуаціях, наприклад, коли потрібне правильне Errorповодження, але метод застосовується з рамки, яка збирає (і відкидає) будь-яку Throwable.