لماذا يمكنني "وهمية" أثر مكدس استثناء في جاوة؟

StackOverflow https://stackoverflow.com/questions/1696765

  •  18-09-2019
  •  | 
  •  

سؤال

إذا قمت بتشغيل الاختبار التالي، فافشل:

public class CrazyExceptions {
    private Exception exception;

    @Before
    public void setUp(){
        exception = new Exception();
    }

    @Test
    public void stackTraceMentionsTheLocationWhereTheExceptionWasThrown(){
        String thisMethod = new Exception().getStackTrace()[0].getMethodName();
        try {
            throw exception;
        }
        catch(Exception e) {
            assertEquals(thisMethod, e.getStackTrace()[0].getMethodName());
        }
    }
}

مع الخطأ التالي:

Expected :stackTraceMentionsTheLocationWhereTheExceptionWasThrown
Actual   :setUp

تتبع المكدس هو مجرد الكذب.

لماذا لا يتم إعادة كتابة تتبع المكدس عند طرح الاستثناء؟ أنا لست جافا ديف، وربما أفتقد شيئا هنا.

هل كانت مفيدة؟

المحلول

يتم إنشاء تتبع المكدس عند إنشاء مثيل للمظهر، وليس عند إلقاءه. هذا هو السلوك المحدد لل مواصفات لغة Java.

20.22.1  public Throwable()

This constructor initializes a newly created Throwable object with null as
its error message string. Also, the method fillInStackTrace (§20.22.5) is
called for this object. 

....

20.22.5  public Throwable fillInStackTrace()

This method records within this Throwable object information about the
current state of the stack frames for the current thread. 

لا أدري، لا أعرف لماذا لقد فعلوا ذلك بهذه الطريقة، ولكن إذا كانت المواصفات تحددها مثل ذلك، فهي تتسق على الأقل في جميع مختلف Java VMS.

ومع ذلك، يمكنك تحديثه عن طريق الاتصال exception.fillInStackTrace() يدويا.

لاحظ أيضا أنه يجب عليك استخدام Thread.currentThread().getStackTrace() بدلا من استخدام new Exception().getStackTrace() (أسلوب سيء).

نصائح أخرى

يتم ملء StackTrace من الاستثناء في وقت إنشاء الاستثناء. خلاف ذلك سيكون من المستحيل قبض استثناء، والتعامل معه و rethrow ذلك. وبعد سوف تضيع stacktrace الأصلي.

إذا كنت ترغب في إجبار هذا عليك الاتصال exception.fillInStackTrace() صراحة.

لأنك لم تطلب إعادة كتابة تتبع المكدس. تم ضبطه عند إنشاءه في طريقة الإعداد، وأنت لم تفعل أي شيء لتغييره.

فئة الاستثناء لا تعطيك أي فرصة لتعيين اسم الطريقة؛ انها ثابتة. لذلك لا توجد طريقة أعرفها حيث يمكنك إعادة تعيين اسم الطريقة، إلا إذا كنت ترغب في اللجوء إلى شيء ما يشبه الانعكاس.

لا يخبرني التوضيحية الخاصة بك إذا كنت تستخدم Junit أو Testng، لأنني لا أستطيع رؤية الاستيراد الثابت، ولكن في أي حال يمكنك تشغيل اختبار لمعرفة ما إذا كان يتم إلقاء استثناء معين باستخدام "المتوقع "عضو في التوضيحية

لا تريد إلقاء استثناء لتغيير مسار المكدس أو لا يمكنك إعادة إلقاء استثناء بأمان.

public void throwsException() {
    throw new RuntimeException();
}

public void logsException() {
    try {
        throwsException();
    } catch (RuntimeException e) {
        e.printStrackTrace();
        throw e; // doesn't alter the exception.
    }
}

@Test
public void youCanSeeTheCauseOfAnException(){
    try {
        logsException();
    } catch(Exception e) {
        e.printStrackTrace(); // shows you the case of the exception, not where it was last re-thrown.
    }
}

يتوافق تتبع المكدس في الاستثناء مع العملية "الجديدة"، لا شيء آخر.

أعتقد أن الافتراض هو أنك لن تكون مفهيا استثناء إلا إذا كنت في عملية رميها، فلماذا دفع الثمن للحصول على تتبع المكدس مرتين؟

سيكون من الصعب إعادة إنشاء تتبع المكدس أثناء إلقاءه، كما هو مجرد إرسال الكائن.

يجب أن يكون الاستثناء قيد الإعداد بالكامل قبل المرمى، لذلك جزء من إنشاء مثيل هو الحصول على تتبع المكدس.

تحديث:

تستطيع الاتصال fillInStackTrace() لحل هذا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top