2012-02-10 24 views
5

Tôi đã đi qua một số nơi trong thư viện java mà tôi đang xây dựng chống lại nơi nguyên nhân của một ngoại lệ được đặt thành ngoại lệ.Có lý do nào để đặt nguyên nhân ngoại lệ cho chính nó không?

Có lý do nào để ngoại lệ tham chiếu chính nó làm nguyên nhân của nó không?

EDIT

Theo yêu cầu, đây là một ví dụ cụ thể:

enter image description here

+2

Thực hành mã hóa không đúng, nếu ngoại lệ là nguyên nhân, nó không phải xác định nguyên nhân gốc. –

+3

Chắc chắn ... nếu bạn muốn * để tạo phụ thuộc vòng tròn mà từ đó không có lối thoát. Tôi bằng cách nào đó nghĩ rằng mã không làm những gì bạn nghĩ rằng nó đang làm. –

+0

Thực hành không tốt, nhưng có thể xảy ra là mã bắt ngoại lệ X và ném một ngoại lệ X mới, với nguyên tắc cũ làm nguyên nhân. Vì vậy, chúng có thể trông giống nhau, nhưng thực sự khác biệt ngoại lệ. – Luciano

Trả lời

2

Không, đó chỉ là thiết kế tồi. Nếu ngoại lệ là nguyên nhân gốc rễ, nó không cần phải xác định nguyên nhân.

Một ngoại lệ có nguyên nhân là trường hợp hợp pháp đối với các trường hợp ngoại lệ khác nhau. Ví dụ, nếu tạo một lưu trữ bền vững, bạn có thể muốn ném một PersistenceExcpetion. Vì vậy, sau đó nếu đó là một cửa hàng tập tin, bạn có thể có nguyên nhân là một IOException. Nếu đó là một cơ sở dữ liệu, có thể nguyên nhân là một SqlException. Etc

3

Từ nguồn Throwable tôi có ở đây:

public synchronized Throwable initCause(Throwable cause) { 
    ... 
    if (cause == this) 
     throw new IllegalArgumentException("Self-causation not permitted"); 
    ... 
} 

Tôi không thấy làm thế nào thiết lập nguyên nhân cho chính nó là có thể ở tất cả.

+0

IIRC, khi tôi thấy điều này, nó đã có ngoại lệ cụ thể từ lớp ORM. Không có lý do gì để tin rằng bởi vì 'Throwable' không cho phép nó trong phương thức 'initCause', ngoại lệ mà tôi đã thấy cũng giống như vậy. – arootbeer

+0

Xem câu trả lời của Pierre Henry để xem nó có thể như thế nào. – ctomek

7

Tôi thường thấy ngoại lệ được ném bởi khung công tác hoặc thư viện chẳng hạn như tham chiếu Hibernate hoặc Spring làm nguyên nhân (gây nhầm lẫn GUI GUI trong quá trình).

Tôi luôn tự hỏi tại sao họ làm điều này vì nó có vẻ như một ý tưởng tồi. Và hôm nay nó thực sự gây ra một vấn đề khi tôi đang cố gắng sắp xếp một thứ tự vào JSON: bam, chu kỳ không cần thiết.

Vì vậy, tôi nghiên cứu nó một chút nữa:

Trong mã nguồn của Throwable (tất cả các mã nguồn được liệt kê ở đây là từ JDK 1.7), chúng tôi có điều này:

/** 
    * The throwable that caused this throwable to get thrown, or null if this 
    * throwable was not caused by another throwable, or if the causative 
    * throwable is unknown. If this field is equal to this throwable itself, 
    * it indicates that the cause of this throwable has not yet been 
    * initialized. 
    * 
    * @serial 
    * @since 1.4 
    */ 
    private Throwable cause = this; 

Bây giờ tôi đặc biệt đáp ứng được vấn đề với một lớp ngoại lệ mở rộng RuntimeException, vì vậy tôi đã đi từ đó. Một trong những nhà xây dựng của RuntimeException:

/** Constructs a new runtime exception with the specified detail message. 
    * The cause is not initialized, and may subsequently be initialized by a 
    * call to {@link #initCause}. 
    * 
    * @param message the detail message. The detail message is saved for 
    *   later retrieval by the {@link #getMessage()} method. 
    */ 
    public RuntimeException(String message) { 
     super(message); 
    } 

Constructor của Exception gọi bằng ở trên:

/** 
    * Constructs a new exception with the specified detail message. The 
    * cause is not initialized, and may subsequently be initialized by 
    * a call to {@link #initCause}. 
    * 
    * @param message the detail message. The detail message is saved for 
    *   later retrieval by the {@link #getMessage()} method. 
    */ 
    public Exception(String message) { 
     super(message); 
    } 

Constructor của Throwable gọi bằng ở trên:

/** 
    * Constructs a new throwable with the specified detail message. The 
    * cause is not initialized, and may subsequently be initialized by 
    * a call to {@link #initCause}. 
    * 
    * <p>The {@link #fillInStackTrace()} method is called to initialize 
    * the stack trace data in the newly created throwable. 
    * 
    * @param message the detail message. The detail message is saved for 
    *   later retrieval by the {@link #getMessage()} method. 
    */ 
public Throwable(String message) { 
    fillInStackTrace(); 
    detailMessage = message; 
} 

fillInStackTrace là một phương pháp tự nhiên và dường như không sửa đổi trường nguyên nhân.

Như bạn có thể thấy, trừ khi phương pháp initCause được gọi sau đó, trường cause không bao giờ được thay đổi từ giá trị ban đầu của this.

Kết luận: nếu bạn tạo mới Exception (hoặc một trong nhiều nhiều lớp con tồn tại trong tự nhiên và không ghi đè hành vi này) bằng cách sử dụng hàm tạo không tham số cause và bạn không gọi phương thức initCause, nguyên nhân của ngoại lệ sẽ là chính nó!

Vì vậy, tôi đoán điều đó sẽ làm cho nó trở thành một sự xuất hiện rất phổ biến.

+1

Bạn thực sự có thể tạo ra một ngoại lệ tự gây ra chỉ làm 'Exception ex = new RuntimeException (" ex ");' Nhưng 'ex.equals (ex.getCause())' sẽ vẫn trả về 'false' vì' Throwable 'implementation:' trả về this.cause == this? null: this.cause; ' – Vladimir

7

Câu trả lời được chấp nhận là gây hiểu nhầm và các câu trả lời khác chưa hoàn thành. Vì vậy ...

Trong khi đó sẽ là thiết kế tồi để vượt qua ngoại lệ vì nguyên nhân riêng, không thể thực hiện Throwable vì lý do chính xác đó. Nguyên nhân hoặc là được truyền vào trong khi xây dựng, hoặc khác với phương thức initCause(), và như được chỉ ra trong câu trả lời thứ hai, nguyên nhân thứ hai sẽ dẫn đến một IllegalArgumentException.

Khi câu trả lời thứ ba chỉ ra, nếu bạn không cung cấp nguyên nhân, nguyên nhân sẽ là này theo triển khai Throwable.

Điều gì có thể bị thiếu (đưa ra câu hỏi ban đầu) là phương thức getCause() của Throwable không bao giờ trả lại này, nó trả về null nếu nguyên nhân == này. Vì vậy, mặc dù trình gỡ lỗi của bạn đang hiển thị số tham chiếu này là nguyên nhân vì nó đang sử dụng sự phản chiếu, khi sử dụng giao diện công cộng của Throwable, bạn sẽ không nhìn thấy nó và do đó sẽ không có vấn đề gì.

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