2012-07-11 43 views
33

Đây có lẽ là một câu hỏi rất ngây thơ.Ngoại lệ không có dấu vết ngăn xếp trong Java

Tôi từng tin rằng Throwable trong Javaluôn luôn chứa theo dõi ngăn xếp. Nó có đúng không? Có vẻ như tôi bắt được exceptionsmà không cần theo dõi ngăn xếp. Nó có ý nghĩa không? Có phải có thể để bắt ngoại lệ mà không có dấu vết ngăn xếp không?

+4

JVM nào? Môi trường? vv Điều này có giúp được không? http://stackoverflow.com/questions/4659151/recurring-exception-without-a-stack-trace-how-to-reset –

+0

@SB. Có, điều này không giúp được gì. Cảm ơn rất nhiều. Tôi có một vấn đề rất giống nhau: Tôi có rất nhiều ngoại lệ (NPE). Phương thức 'error' của' log4j' ghi lại một số ngoại lệ _without_ dấu vết ngăn xếp. – Michael

Trả lời

27

Có thể bắt một đối tượng Throwable trong Java mà không có một stack trace:

Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace) 

Constructs một Throwable mới với định thông điệp cụ thể, nguyên nhân, ức chế kích hoạt hay vô hiệu hóa, và ghi stack trace đã bật hoặc tắt.

http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html

20

Đối với Java 6:

Như Java 6 không có constructor Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace), chúng ta có thể ngăn chặn các điền stacktrace sử dụng dưới đây kỹ thuật (mượn từ Scala, đã biết từ How slow are Java exceptions?)

class NoStackTraceRuntimeException extends RuntimeException { 
    @Override 
    public synchronized Throwable fillInStackTrace() { 
     return this; 
    } 
} 

Cách sử dụng tương tự: throw new NoStackTraceRuntimeException() hoặc loại phụ của nó.

Chúng tôi cũng có thể làm tương tự bằng cách mở rộng Throwable:

class NoStackTraceThrowable extends Throwable { 
    @Override 
    public synchronized Throwable fillInStackTrace() { 
     return this; 
    } 
} 

Nhưng, một bắt nhỏ là bạn không còn có thể catch những ngoại lệ sử dụng Exception như đây không phải là subtype của Exception, thay vào đó nên bắt NoStackTraceThrowable hoặc đó là các kiểu con.

Cập nhật: Đối với một số số liệu thống kê thú vị về hiệu suất trong usecases khác nhau, kiểm tra này SO question

+0

OP thực sự đề cập đến java-6 trong câu hỏi của anh ấy !!! –

+4

@shekharsuman Không, nhưng không phải Java 7. Câu trả lời này có thể giúp ai đó với Java 6 :) – manikanta

+2

Ngay cả bên ngoài Java 1.6, đây vẫn là một phương pháp khả thi. Điều này sẽ ngăn chặn toàn bộ dấu vết ngăn xếp (như được truyền trong 'nguyên nhân' của hàm tạo tham số 4 sẽ được in ra). – DBK

6

Đối với Java 7+, đây là một ví dụ về một ngoại lệ nơi stack trace tùy chọn có thể được dập tắt.

public class SuppressableStacktraceException extends Exception { 

    private boolean suppressStacktrace = false; 

    public SuppressableStacktraceException(String message, boolean suppressStacktrace) { 
     super(message, null, suppressStacktrace, !suppressStacktrace); 
     this.suppressStacktrace = suppressStacktrace; 
    } 

    @Override 
    public String toString() { 
     if (suppressStacktrace) { 
      return getLocalizedMessage(); 
     } else { 
      return super.toString(); 
     } 
    } 
} 

này có thể được chứng minh với:

try { 
    throw new SuppressableStacktraceException("Not suppressed", false); 
} catch (SuppressableStacktraceException e) { 
    e.printStackTrace(); 
} 
try { 
    throw new SuppressableStacktraceException("Suppressed", true); 
} catch (SuppressableStacktraceException e) { 
    e.printStackTrace(); 
} 

này được dựa trên MLContextException từ Apache SystemML, mã số đó là có sẵn trên GitHub tại https://github.com/apache/systemml.

0

Cách đơn giản nhất để ngăn chặn các stacktrace trên bất kỳ ngoại lệ là

throwable.setStackTrace(new StackTraceElement[0]); 

Nếu ngoại lệ có một nguyên nhân, bạn có thể cần phải làm như vậy một cách đệ quy.

cũng Điều này làm giảm việc tạo ra tốn kém của ngăn xếp dấu vết, càng nhiều càng tốt

Các stacktrace cho một Throwable được khởi tạo trong

Throwable#fillInStackTrace() 

, được gọi bởi bất kỳ nhà xây dựng và do đó không thể tránh. Khi stacktrace thực sự được sử dụng, một StackTraceElement [] đang uể oải xây dựng vào năm

Throwable#getOurStackTrace() 

mà chỉ xảy ra, nếu Throwable.stackTrace lĩnh vực không phải là đã thiết lập.

Đặt stacktrace thành bất kỳ giá trị không null nào, tránh việc xây dựng StackTraceElement [] trong Throwable # getOurStackTrace() và giảm hiệu suất phạt càng nhiều càng tốt.

+1

Điều này làm việc, nhưng nó không giải quyết được vấn đề mà hầu hết mọi người muốn giải quyết bằng cách ngăn chặn các dấu vết ngăn xếp. Tạo dấu vết ngăn xếp chậm và điều này có thể làm chậm mã sử dụng ngoại lệ rất nhiều để nhắn tin. Để giải quyết vấn đề này, người ta phải ngăn chặn việc tạo ra các dấu vết ngăn xếp, không xóa chúng khi chúng đã được tạo ra. - Điều đó nói rằng, cách tiếp cận của bạn vẫn có thể hữu ích để tiết kiệm bộ nhớ khi có rất nhiều ngoại lệ mà người khác không có quyền kiểm soát được lưu trữ vì một lý do nào đó. –

+0

Halo @Hans Adler, tôi hiểu mối lo ngại của bạn, nhưng tôi nghĩ rằng câu trả lời của tôi cũng làm giảm việc tạo ra dấu vết tốn kém, càng nhiều càng tốt.Xin vui lòng xem bản chỉnh sửa cuối cùng của tôi. –

Các vấn đề liên quan