ChuckNorrisException ที่จับไม่ได้


596

เป็นไปได้ไหมที่จะสร้างส่วนของโค้ดในJavaที่จะทำให้ไม่สามารถจับสมมุติฐานได้java.lang.ChuckNorrisException?

ความคิดที่อยู่ในใจคือการใช้ตัวอย่างเช่นตัวดักหรือการเขียนโปรแกรมเชิงกว้าง



2
ใช้คำแนะนำจากลิงค์ @jschoen ที่ให้ไว้ (ปิดการใช้งานตัวตรวจสอบรหัสไบต์) คุณสามารถโยนสิ่งที่ไม่ขยาย Throwable! อธิบายไว้ในคำตอบของฉันด้านล่าง
jtahlborn

4
ข้อความที่ตัดตอนมาจากคำตอบของ aioobe สรุปคำถาม @jschoen ที่เชื่อมโยงค่อนข้างดี: "Ie คำถามของคุณสามารถตีความได้ว่า 'หาก JVM เบี่ยงเบนจากสเปคมันสามารถทำสิ่งแปลก ๆ ได้หรือไม่และคำตอบนั้นแน่นอน ใช่."
Dan Is Fiddling โดย Firelight

2
@Max - คุณสามารถอธิบายอย่างละเอียดเกี่ยวกับการใช้งานจริงสำหรับสิ่งนี้ได้หรือไม่?
Vineet Bhatia

3
วิธีการเกี่ยวกับข้อยกเว้นที่ rethrow ตัวเองบนfinalize()?
Lie Ryan

คำตอบ:


314

ฉันไม่ได้พยายามนี้ดังนั้นผมจึงไม่ทราบว่า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"

18
ตกลงดังนั้นสิ่งที่ถ้าคุณจับObjectแทนThrowableแล้ว? (คอมไพเลอร์จะไม่อนุญาต แต่เนื่องจากเราได้ปิดการใช้งานตัวตรวจสอบแล้วอาจมีใครสามารถแฮ็กรหัส bytecode ได้)
Ilmari Karonen

11
ตามสิ่งที่คุณสามารถโยนใน Javaคุณยังสามารถจับสิ่งที่ไม่ได้ขยายได้ แต่การขว้างและจับมันเป็นพฤติกรรมที่ไม่ได้กำหนด
VolatileDream

8
@dzieciou พวกเขาสามารถเป็นจริงด้วยกัน คุณอาจสามารถจับพวกมันได้โดยใช้เวอร์ชันของสภาวะแวดล้อม Java ของคุณกับเวอร์ชันของระบบปฏิบัติการตามประเภทโปรเซสเซอร์ของคุณ แต่ถ้ามันไม่ได้ระบุในมาตรฐานไม่ว่าจะสามารถถูกจับได้ก็เรียกว่าพฤติกรรมที่ไม่ได้กำหนดเนื่องจากการใช้งานอื่น ๆ ของ Java อาจเลือกที่จะไม่ให้จับได้
heinrich5991

2
Hmmph ฉันหวังว่าสำหรับ 176 upvotes คุณจะเขียนโค้ด JNI บางตัวที่ Monkey-patch เรียก call stack ทั้งหมดเพื่อ rethrow ข้อยกเว้นของคุณ (เรียกโดย ctor แน่นอน)
kdgregory

3
เมื่อทำทั้งหมดนี้เป็นความคิดที่ดีที่จะยืนบนขาข้างหนึ่งตบหัวของคุณและลูบหน้าท้องของคุณในขณะที่ผิวหน้าเบ้ง ... ;););)
เกลนที่ดีที่สุด

120

หลังจากไตร่ตรองสิ่งนี้แล้วฉันได้สร้างข้อยกเว้นที่ไม่สามารถจับตาดูได้สำเร็จ ฉันเลือกที่จะตั้งชื่อมัน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)
    {

    }
}

ทำให้เกิดการล้นสแต็ก - อีกครั้งข้อยกเว้นยังคงไม่ถูกตรวจสอบ


32
+1 สำหรับการใช้ Stack Overflow ในคำตอบของคุณ แค่ล้อเล่นคำตอบที่ดีจริงๆ
โยสิยาห์

7
"ข้อยกเว้นที่ไม่สามารถจับตาดูได้" ที่เหมาะสมจะช่วยให้มั่นใจว่าการปิดล้อมในที่สุดบล็อกทั้งหมดจะดำเนินการโดยไม่มีการจับ การฆ่าระบบไม่ได้ทำให้เกิดข้อยกเว้น แต่เป็นการฆ่าระบบ
supercat

4
คุณ "โยน" JulesWinfieldอย่างไร ระบบจะไม่หยุดร้องเสียงกรี๊ดก่อนที่มันจะถูกโยนทิ้ง?
supercat

6
@mikeTheLiar: ระบบออกระหว่าง Constructor ใช่ไหม? คำสั่งthrow new Whatever()นั้นมีสองส่วน: Whatever it = new Whatever(); throw it;และระบบจะตายก่อนที่จะถึงส่วนที่สอง
supercat

5
@mikeTheLiar คุณสามารถจับ Jules หรือ Vincent ได้อย่างง่ายดาย ... ถ้าคุณจัดการที่จะโยนมัน มันง่ายที่จะสร้างข้อยกเว้นที่คุณไม่สามารถโยนได้:class cn extends exception{private cn(){}}
John Dvorak

85

ด้วยข้อยกเว้นดังกล่าวมันจะเห็นได้ชัดว่าจำเป็นต้องใช้ a System.exit(Integer.MIN_VALUE);จากนวกรรมิกเพราะนี่คือสิ่งที่จะเกิดขึ้นถ้าคุณโยนข้อยกเว้นเช่น;)


32
+1; IMO นี่เป็นทางออกที่เป็นไปได้เท่านั้น ข้อยกเว้นที่ไม่สามารถตรวจจับได้คือควรยกเลิกโปรแกรม ...
home

7
ไม่มันจะไม่เกิดอะไรขึ้นเมื่อคุณโยนข้อยกเว้น ข้อยกเว้นที่ไม่ได้ตรวจสอบจะยุติเธรดเดี่ยว แต่จะไม่ออกจาก jvm ในบางบริบทของ System.exit เองจะทำให้ SecurityException ไม่ใช่รหัสทุกชิ้นที่ได้รับอนุญาตให้ปิดโปรแกรม
josefx

3
คุณสามารถใช้แทนwhile(true){} System.exit()
Piotr Praszmo

2
จริงๆแล้วคุณสามารถป้องกันไม่ให้System.exit()ทำงานโดยการติดตั้งตัวจัดการความปลอดภัยซึ่งไม่อนุญาต ที่จะเปลี่ยน Constructor ให้เป็นข้อยกเว้นอื่น (SecurityException) ซึ่งสามารถตรวจจับได้
jtahlborn

5
Umm เทคนิคที่คุณไม่เคยโยนข้อยกเว้น คุณยังไม่ได้สร้างวัตถุที่จะโยน!
Thomas Eding

46

รหัสใด ๆ ที่สามารถจับได้ Throwable ดังนั้นไม่มีข้อยกเว้นใด ๆ ที่คุณสร้างขึ้นจะเป็นประเภทย่อยของ Throwable และจะถูกจับได้


11
Throwable จะhangพยายามที่จะจับ ChuckNorrisException: P
PermGenError

35
public class ChuckNorrisException extends Exception {
    public ChuckNorrisException() {
        System.exit(1);
    }
}

(จริงอยู่ที่ข้อยกเว้นทางเทคนิคนี้จะไม่ถูกโยนลงไป แต่ChuckNorrisExceptionจะไม่สามารถโยนทิ้งได้ แต่จะเป็นการโยนคุณก่อน)


4
เพื่อนร่วมงานของฉันแนะนำให้ติด 'for (;;) {}' เนื่องจากเขารู้สึกว่าการโทร 'System.exit (1)' อาจทำให้เกิดข้อยกเว้นด้านความปลอดภัย ฉันลงคะแนนสำหรับความคิดสร้างสรรค์นี้!
Phil Street

ฉันเห็นด้วยกับคำตอบสุดท้ายของคุณ ไม่ยุ่งกับ ChuckNorris ยกเว้นหรือไม่
30432

28

ข้อยกเว้นใด ๆ ที่คุณโยนจะต้องขยาย Throwable ดังนั้นจึงสามารถจับได้เสมอ ดังนั้นคำตอบคือไม่

หากคุณต้องการที่จะทำให้มันยากที่จะจัดการคุณสามารถแทนที่วิธีการgetCause(), getMessage(), getStackTrace(), ที่จะโยนอีกtoString()java.lang.ChuckNorrisException


2
อืมจับได้ (Throwable t) เรียกวิธีการใด ๆ หรือมิฉะนั้นกลายพันธุ์วัตถุ? อาจเป็นไปได้ที่จะทำให้ประโยคจับเพื่อโยนข้อยกเว้นเพิ่มเติมเพื่อให้เป็นไปไม่ได้
Colton

1
ผมคิดว่าcatch(Throwable t)ร้านค้าเพียงลงในตัวแปรเพื่อให้ข้อเสนอแนะของฉันเท่านั้นนำไปใช้ในบล็อกถัดไปเมื่อผู้ใช้ต้องการที่จะรับมือกับการยกเว้น
mirelon

24

คำตอบของฉันอยู่บนพื้นฐานของความคิด @ 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

ไม่แปลกใจเลยว่ามันเป็นการเตะแบบวงกว้าง :)


ดีมาก! ยังไม่ได้ทำอะไรมากกับการจัดการคำจำกัดความของชั้นเรียนด้วยตัวเอง คุณยังต้องการ "ตรวจสอบ: ไม่มี" ใน commandline หรือไม่
jtahlborn

@jtahlborn ใช่พยายามที่จะโยนวัตถุที่ไม่ได้เป็นลูกหลานของ Throwable ล้มเหลวโดยไม่ต้อง "ตรวจสอบ: ไม่มี"
ไฟป่า

โอ้ฉันได้รับความประทับใจที่ว่านี้ก็มีข้อ จำกัด แล้วสิ่งนี้แตกต่างจากคำตอบของฉันอย่างไร
jtahlborn

2
ข้อแตกต่างที่สำคัญคือมันใช้งานโค้ดจาวาได้โดยไม่ต้องแฮ็คเวลาคอมไพล์
Wildfire

15

ใน Constructor คุณสามารถเริ่มหัวข้อซึ่งเรียกซ้ำ ๆ originalThread.stop (ChuckNorisException.this)

ด้ายสามารถจับข้อยกเว้นซ้ำ ๆ แต่จะยังคงขว้างมันจนกว่าจะตาย


13

ไม่ได้ข้อยกเว้นทั้งหมดใน Java ต้องเป็นคลาสย่อยjava.lang.Throwableและถึงแม้ว่ามันอาจจะไม่ใช่แนวปฏิบัติที่ดี แต่คุณสามารถตรวจสอบข้อยกเว้นทุกประเภทได้เช่น:

try {
    //Stuff
} catch ( Throwable T ){
    //Doesn't matter what it was, I caught it.
}

ดูเอกสารประกอบjava.lang.Throwableสำหรับข้อมูลเพิ่มเติม

หากคุณพยายามหลีกเลี่ยงข้อยกเว้นที่เลือก (สิ่งที่ต้องได้รับการจัดการอย่างชัดเจน) คุณจะต้องการข้อผิดพลาดระดับรองหรือ RuntimeException


9

จริงๆแล้วคำตอบที่ยอมรับนั้นไม่ค่อยดีนักเพราะจาวาต้องทำงานโดยไม่มีการยืนยันเช่นรหัสจะไม่ทำงานภายใต้สถานการณ์ปกติ

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)

8

ตัวแปรในชุดรูปแบบเป็นข้อเท็จจริงที่น่าประหลาดใจที่คุณสามารถโยนข้อยกเว้นที่ไม่ได้ประกาศและตรวจสอบได้จากโค้ด 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 เป็นข้อยกเว้นที่ตรวจสอบ


6

เพียงChuckNorrisExceptionใน Java ควรจะเป็นและOutOfMemoryErrorStackOverflowError

จริงๆคุณสามารถ "จับ" พวกเขาในวิธีที่catch(OutOfMemoryError ex)จะดำเนินการในกรณีที่มีข้อยกเว้นจะถูกโยน แต่บล็อกนั้นจะ rethrow ข้อยกเว้นให้กับผู้โทรโดยอัตโนมัติ

ฉันไม่คิดว่านั่นpublic class ChuckNorrisError extends Errorเป็นการหลอกลวง แต่คุณสามารถลองดูได้ ฉันไม่พบเอกสารเกี่ยวกับการขยายError


2
ข้อผิดพลาดยังคงขยายได้ Throwable ดังนั้นจึงไม่มีวิธีป้องกันการจับ นั่นคือโดยการออกแบบภาษาจาวา
JasonM1

1
@ JasonM1 ฉันไม่คิดว่า OP ขอข้อยกเว้น "uncatchable" จริง ๆ และฉันหมายความว่าข้อผิดพลาดแพร่กระจายแม้ว่าคุณจะจับมัน ดังนั้น Throwable ใด ๆ สามารถจับได้ แต่ในที่สุดทั้งสองนี้จะเผยแพร่ไม่ว่าคุณจะทำอะไรก็ตาม
usr-local-ΕΨΗΕΛΩΝ

หากต้องการ ChuckNorrisException สามารถขยาย Throwable ได้โดยตรงจากนั้นจะไม่มีข้อยกเว้นหรือข้อผิดพลาด!
JasonM1

4
ข้อผิดพลาดไม่เผยแพร่แม้ว่าคุณจะจับมันฉันไม่แน่ใจว่าคุณมีความคิดนั้นอยู่ที่ไหน
jtahlborn

3
ฉันคิดว่าคุณสับสนเกี่ยวกับ Erros พวกเขาเป็นข้อยกเว้นปกติเหมือนทุกอย่างที่ขยายได้ Throwable หรือ Throwable เอง
bestsss

6

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ทำไม? วัตถุที่ไม่สามารถถอนได้นั้นไม่สามารถจับได้โดยการกำหนดเพราะคุณไม่สามารถจับอะไรที่ไม่เคยถูกโยนทิ้ง


2
แต่มันก็ไม่ใช่ข้อยกเว้น
dolbi

8
@dolbi: ฉันไม่สามารถหาสถานที่ในคำถามของ OP ที่ระบุว่าjava.lang.ChuckNorrisExceptionจะต้องเป็นข้อยกเว้นปล่อยให้อยู่คนเดียว
โยนได้

1
ฉันเดาว่ามันไม่ได้ระบุ แต่มันส่อให้เห็น คุณเป็นนักคณิตศาสตร์ :-) ใช่มั้ย
dolbi

3

คุณสามารถให้ ChuckNorris เป็นส่วนตัวหรือเป็นส่วนตัวและซ่อนเขาหรือตามเขาไป ...

try { doChuckAction(); } catch(ChuckNorrisException cne) { /*do something else*/ }


7
ฉันไม่เชื่อความคิดที่จะจับมัน ฉันคิดว่าความคิดคือการป้องกันไม่ให้ถูกจับ
Patrick Roberts เมื่อ

ถูกต้องฉันถ้าฉันผิด แต่ถ้าคุณทำให้มันอยู่ภายในคุณไม่สามารถไปได้โดยไม่ต้องสะท้อน
Jay

5
ใช่ แต่ตราบใดที่คุณสามารถจับยกเว้นหรือ Throwable การมองเห็นของประเภทที่แท้จริงนั้นไม่เกี่ยวข้อง
KeithS

3

ปัญหาพื้นฐานสองประการที่มีการจัดการข้อยกเว้นใน Java คือมันใช้ประเภทของข้อยกเว้นเพื่อระบุว่าควรดำเนินการตามหรือไม่และสิ่งใดก็ตามที่ดำเนินการตามข้อยกเว้น (เช่น "catch" es it) จะถูกสันนิษฐานเพื่อแก้ไข เงื่อนไขพื้นฐาน มันจะมีประโยชน์ที่จะมีวิธีการที่วัตถุข้อยกเว้นสามารถตัดสินใจว่าตัวจัดการที่ควรดำเนินการและไม่ว่าตัวจัดการที่ได้ดำเนินการจนถึงขณะนี้มีการทำความสะอาดสิ่งต่าง ๆ เพียงพอสำหรับวิธีการปัจจุบันเพื่อตอบสนองเงื่อนไขการออก ในขณะที่สิ่งนี้สามารถนำมาใช้เพื่อสร้างข้อยกเว้น "ที่ไม่สามารถจับตาดูได้" แต่การใช้ที่ใหญ่กว่าสองประการคือ (1) สร้างข้อยกเว้นที่จะได้รับการพิจารณาเมื่อจัดการด้วยรหัสที่รู้วิธีจัดการกับพวกเขาจริง ๆfinallyFooExceptionระหว่างfinallyบล็อกในระหว่างการคลี่คลายของ a BarException, ข้อยกเว้นทั้งสองควรเผยแพร่สายสแต็ค; ทั้งสองควรจับได้ แต่ไม่ควรคลี่คลายจนกว่าจะถูกจับได้ทั้งคู่) น่าเสียดายที่ฉันไม่คิดว่าจะมีวิธีใดที่จะทำให้โค้ดการจัดการข้อยกเว้นที่มีอยู่ใช้งานได้โดยไม่ทำให้เกิดความเสียหาย


ความคิดที่น่าสนใจ แต่ฉันไม่คิดว่ารหัสระดับต่ำจะรู้ว่าข้อยกเว้น "หมายถึง" สำหรับผู้โทรดังนั้นฉันจึงไม่คิดว่ามันจะเหมาะสมสำหรับผู้โยนที่จะตัดสินใจว่าตัวจัดการควรดำเนินการอย่างไร
jtahlborn

@jtahlborn: ตอนนี้ผู้โยนตัดสินใจว่าตัวจัดการข้อยกเว้นควรดำเนินการผ่านทางเลือกประเภทการยกเว้น สิ่งนี้ทำให้ทุกอย่าง แต่เป็นไปไม่ได้ที่จะจัดการกับบางสถานการณ์อย่างหมดจด เหนือสิ่งอื่นใด: (1) หากมีข้อยกเว้นเกิดขึ้นในขณะที่finallyบล็อกกำลังล้างข้อมูลจากข้อยกเว้นก่อนหน้านี้ค่อนข้างเป็นไปได้ว่าอาจมีข้อยกเว้นอย่างใดอย่างหนึ่งในกรณีที่ไม่มีข้อยกเว้นอื่น ๆ แต่การจัดการอย่างใดอย่างหนึ่งและการเพิกเฉยอีกฝ่ายนั้นจะไม่ดี แม้ว่าจะไม่มีกลไกในการสร้างข้อยกเว้นแบบคอมโพสิตที่ตัวจัดการทั้งสองจะประมวลผล
supercat

@ jtahlborn: นอกจากนี้มันทำให้ยากมากที่จะอนุญาตให้มีข้อยกเว้นที่เกิดขึ้นใน callbacks เพื่อจัดการกับเลเยอร์แอปพลิเคชันด้านนอก หากข้อยกเว้นของการติดต่อกลับถูกห่อในประเภทยกเว้นอื่นประเภทของข้อยกเว้นการโทรกลับไม่สามารถใช้ในชั้นนอกในการตัดสินใจว่าจะจับมัน; หากไม่มีการห่อข้อยกเว้นมิด "เลเยอร์" อาจถูกเข้าใจผิดสำหรับสิ่งที่เกิดขึ้นในการเรียกกลับ หากมีการแจ้งให้ทราบว่าวัตถุข้อยกเว้นที่ถูกห่อเมื่อถูกส่งผ่านไปยังชั้นแอปพลิเคชันด้านนอกมันจะสามารถเริ่มตอบประเภทของข้อยกเว้นที่ห่อไว้ได้
supercat

ฉันไม่ได้โต้เถียงประเด็นอื่น ๆ ของคุณเพียงแค่คำสั่งเกี่ยวกับวัตถุข้อยกเว้นที่จะตัดสินใจว่าตัวจัดการใดจะทำงาน มีข้อยกเว้นบางประเภทที่ทำเช่นนั้น แต่ดูเหมือนว่าคุณต้องการบางสิ่งบางอย่างที่มีพลวัตมากขึ้นซึ่งฉันไม่เห็นด้วย ฉันคิดว่าข้อโต้แย้งหลักของคุณ (ซึ่งคุณกำลังจะมาที่ด้านข้าง) คือการรวบรวมข้อมูลให้มากที่สุดเท่าที่จะทำได้ที่ด้านล่างและให้เลเยอร์ด้านบนดูและทำงานกับข้อมูลทั้งหมดนั้น ในประเด็นทั่วไปนี้ฉันเห็นด้วยกับคุณ แต่มารอยู่ในรายละเอียด / การดำเนินการ
jtahlborn

@ jtahlborn: ความตั้งใจของฉันคือการไม่ใช้วิธีการเสมือนจริงในการดำเนินการใด ๆ โดยเฉพาะ "ไดนามิก" แต่โดยพื้นฐานแล้วจะพูดว่า "มีเงื่อนไขของประเภทที่ระบุซึ่งควรดำเนินการหรือไม่" สิ่งหนึ่งที่ฉันลืมพูดถึงคือว่าควรมีวิธีการที่รหัสที่โทรFooสามารถแยกความแตกต่างระหว่างข้อยกเว้นที่Fooทั้งตัวเองโยนหรือจงใจต้องการแกล้งมันตัวเองจากสิ่งที่Fooไม่ได้คาดหวังว่าจะเกิดขึ้นเมื่อมัน เรียกวิธีอื่น นั่นคือสิ่งที่ความคิดของข้อยกเว้น "ตรวจสอบ" ควรเป็น "เกี่ยวกับ"
supercat

1

เป็นไปได้อย่างง่ายดายที่จะจำลองข้อยกเว้นที่ไม่ได้ตรวจสอบบนเธรดปัจจุบัน สิ่งนี้จะทริกเกอร์พฤติกรรมปกติของข้อยกเว้นที่ไม่ถูกตรวจจับและทำให้งานสำเร็จตามความหมาย อย่างไรก็ตามจะไม่จำเป็นต้องหยุดการดำเนินการของเธรดปัจจุบันเนื่องจากจะไม่มีข้อยกเว้นเกิดขึ้นจริง

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ใด ๆ


0

เรียกใช้ System.exit (1) ในfinalizeและเพียงแค่คัดลอกข้อยกเว้นจากวิธีอื่นทั้งหมดเพื่อให้โปรแกรมออกจาก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.