เป็นไปได้ไหมที่จะสร้างส่วนของโค้ดในJavaที่จะทำให้ไม่สามารถจับสมมุติฐานได้java.lang.ChuckNorrisException
?
ความคิดที่อยู่ในใจคือการใช้ตัวอย่างเช่นตัวดักหรือการเขียนโปรแกรมเชิงกว้าง
finalize()
?
เป็นไปได้ไหมที่จะสร้างส่วนของโค้ดในJavaที่จะทำให้ไม่สามารถจับสมมุติฐานได้java.lang.ChuckNorrisException
?
ความคิดที่อยู่ในใจคือการใช้ตัวอย่างเช่นตัวดักหรือการเขียนโปรแกรมเชิงกว้าง
finalize()
?
คำตอบ:
ฉันไม่ได้พยายามนี้ดังนั้นผมจึงไม่ทราบว่าJVMจะ จำกัด บางอย่างเช่นนี้ แต่บางทีคุณอาจจะรวบรวมรหัสที่พ่นChuckNorrisException
แต่ที่รันไทม์ให้กำหนดระดับของการChuckNorrisException
ที่ไม่ขยาย Throwable
UPDATE:
มันไม่ทำงาน มันสร้างข้อผิดพลาดการตรวจสอบ:
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
แล้ว? (คอมไพเลอร์จะไม่อนุญาต แต่เนื่องจากเราได้ปิดการใช้งานตัวตรวจสอบแล้วอาจมีใครสามารถแฮ็กรหัส bytecode ได้)
หลังจากไตร่ตรองสิ่งนี้แล้วฉันได้สร้างข้อยกเว้นที่ไม่สามารถจับตาดูได้สำเร็จ ฉันเลือกที่จะตั้งชื่อมันJulesWinnfield
แทน Chuck เพราะมันเป็นหนึ่งในข้อยกเว้นการวางไข่ของเห็ดเมฆ ยิ่งไปกว่านั้นมันอาจจะไม่ใช่สิ่งที่คุณคิดไว้ในใจ แต่ก็ไม่สามารถจับได้ สังเกต:
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");
}
}
และ 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()
ทำงานโดยการติดตั้งตัวจัดการความปลอดภัยซึ่งไม่อนุญาต ที่จะเปลี่ยน Constructor ให้เป็นข้อยกเว้นอื่น (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 ผิดพลาดตั้งแต่เริ่มต้น (Chuck ชอบการพัง 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
ไม่แปลกใจเลยว่ามันเป็นการเตะแบบวงกว้าง :)
ใน Constructor คุณสามารถเริ่มหัวข้อซึ่งเรียกซ้ำ ๆ 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
จริงๆแล้วคำตอบที่ยอมรับนั้นไม่ค่อยดีนักเพราะจาวาต้องทำงานโดยไม่มีการยืนยันเช่นรหัสจะไม่ทำงานภายใต้สถานการณ์ปกติ
AspectJ เพื่อช่วยเหลือสำหรับทางออกที่แท้จริง !
คลาสข้อยกเว้น:
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 เป็นข้อยกเว้นที่ตรวจสอบ
เพียงChuckNorrisException
ใน Java ควรจะเป็นและOutOfMemoryError
StackOverflowError
จริงๆคุณสามารถ "จับ" พวกเขาในวิธีที่catch(OutOfMemoryError ex)
จะดำเนินการในกรณีที่มีข้อยกเว้นจะถูกโยน แต่บล็อกนั้นจะ rethrow ข้อยกเว้นให้กับผู้โทรโดยอัตโนมัติ
ฉันไม่คิดว่านั่น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
จะต้องเป็นข้อยกเว้นปล่อยให้อยู่คนเดียว
คุณสามารถให้ ChuckNorris เป็นส่วนตัวหรือเป็นส่วนตัวและซ่อนเขาหรือตามเขาไป ...
try { doChuckAction(); } catch(ChuckNorrisException cne) { /*do something else*/ }
ปัญหาพื้นฐานสองประการที่มีการจัดการข้อยกเว้นใน Java คือมันใช้ประเภทของข้อยกเว้นเพื่อระบุว่าควรดำเนินการตามหรือไม่และสิ่งใดก็ตามที่ดำเนินการตามข้อยกเว้น (เช่น "catch" es it) จะถูกสันนิษฐานเพื่อแก้ไข เงื่อนไขพื้นฐาน มันจะมีประโยชน์ที่จะมีวิธีการที่วัตถุข้อยกเว้นสามารถตัดสินใจว่าตัวจัดการที่ควรดำเนินการและไม่ว่าตัวจัดการที่ได้ดำเนินการจนถึงขณะนี้มีการทำความสะอาดสิ่งต่าง ๆ เพียงพอสำหรับวิธีการปัจจุบันเพื่อตอบสนองเงื่อนไขการออก ในขณะที่สิ่งนี้สามารถนำมาใช้เพื่อสร้างข้อยกเว้น "ที่ไม่สามารถจับตาดูได้" แต่การใช้ที่ใหญ่กว่าสองประการคือ (1) สร้างข้อยกเว้นที่จะได้รับการพิจารณาเมื่อจัดการด้วยรหัสที่รู้วิธีจัดการกับพวกเขาจริง ๆfinally
FooException
ระหว่าง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
ใด ๆ
เรียกใช้ System.exit (1) ในfinalize
และเพียงแค่คัดลอกข้อยกเว้นจากวิธีอื่นทั้งหมดเพื่อให้โปรแกรมออกจาก