2010-04-08 7 views
8

Tại sao Java không cho phép gán giá trị cho biến cuối cùng trong khối catch sau khi đặt giá trị trong khối thử, ngay cả khi nó không có thể cho giá trị cuối cùng được viết trong trường hợp ngoại lệ.Gán giá trị mặc định cho biến cuối cùng trong trường hợp ngoại lệ trong Java

Dưới đây là một ví dụ mà chứng tỏ vấn đề:

public class FooBar { 

    private final int foo; 

    private FooBar() { 
     try { 
      int x = bla(); 
      foo = x; // In case of an exception this line is never reached 
     } catch (Exception ex) { 
      foo = 0; // But the compiler complains 
        // that foo might have been initialized 
     } 
    } 

    private int bla() { // You can use any of the lines below, neither works 
     // throw new RuntimeException(); 
     return 0; 
    } 
} 

Vấn đề là không khó để làm việc xung quanh, nhưng tôi muốn hiểu lý do tại sao các trình biên dịch không chấp nhận điều này.

Cảm ơn trước về mọi thông tin đầu vào!

+2

Vâng, nếu bạn đang nắm bắt được 'Ngoại lệ 'chung thì có thể có điều gì xảy ra ngay sau/trong khi' foo = x' có thể ném một ngoại lệ không? Có lẽ trình biên dịch là "chơi nó an toàn"? – FromCanada

+0

Vâng đó là câu hỏi. Nhưng tôi thực sự nghi ngờ rằng một nhiệm vụ có thể dẫn đến một ngoại lệ bị ném và vẫn viết một giá trị cho biến đó. – Alfonso

+2

Nơi bạn nói "Trong trường hợp ngoại lệ dòng này không bao giờ đạt được" Tôi nghi ngờ rằng trình biên dịch từ chối biết ý định của bạn đến mức độ chi tiết đó. Vì vậy, tất cả những gì nó thấy là foo được chỉ định hai lần. Có lẽ lý do là, điều này cho phép trình biên dịch tối ưu hóa mã xuống foo = bla(), vì x cuối cùng là thừa không? Chỉ cần suy đoán. – greim

Trả lời

7
try { 
    int x = bla(); 
    foo = x; // In case of an exception this line is never reached 
} catch (Exception ex) { 
    foo = 0; // But the compiler complains 
      // that foo might have been initialized 
} 

Lý do là vì trình biên dịch không thể suy ra rằng ngoại lệ chỉ có thể được ném trước khi foo được initalized. Ví dụ này là một trường hợp đặc biệt, nếu nó là rõ ràng rằng đó là sự thật, nhưng hãy cân nhắc:

try { 
    int x = bla(); 
    foo = x; // In case of an exception this line is never reached...or is it? 
    callAnotherFunctionThatThrowsAnException(); // Now what? 
} catch (Exception ex) { 
    foo = 0; // But the compiler complains 
      // that foo might have been initialized, 
      // and now it is correct. 
} 

Để viết một trình biên dịch để xử lý những trường hợp rất cụ thể như thế này sẽ là một nhiệm vụ to lớn - có khả năng rất nhiều trong số họ.

+0

Tôi đoán đó là vấn đề ở đây. Bài tập phải là sau bất kỳ câu nào có thể có phản ứng phụ, mà tôi đoán sẽ không quá khó để kiểm tra, nhưng mặt khác nó không thực sự cần thiết vì bạn có thể làm việc xung quanh dễ dàng (nếu có chút xấu xí). – Alfonso

0

Làm thế nào về một ném Error?

+0

Phải, hãy thử bắt Throwable để thay thế. Nếu nó sẽ cho bạn. – bmargulies

+0

Điều này sẽ lan truyền ra khỏi khối try-catch và dẫn đến một ngoại lệ tại người gọi của 'new FooBar();'. Vì vậy, biến cuối cùng sẽ không bao giờ được viết. Nhưng trong trường hợp của tôi trình biên dịch phàn nàn rằng biến có thể được viết hai lần, đó chắc chắn không phải là trường hợp. – Alfonso

+0

Vâng, bạn nói đúng. Tôi đã hiểu sai câu hỏi. Tôi thực sự cũng bị kích thích bởi điều này. – lexicore

2

Để là người đi bộ, Thread.stop(Throwable) có thể ném ngoại lệ ngay sau khi chuyển nhượng khối thử.

Tuy nhiên, các quy tắc có nhiệm vụ nhất định và các thuật ngữ đồng minh đủ phức tạp. Kiểm tra JLS. Cố gắng thêm nhiều quy tắc sẽ làm phức tạp ngôn ngữ và không mang lại lợi ích đáng kể.

+0

Wow, tôi không biết về Thread.stop (Throwable). Đây phải là phương pháp tà ác nhất trong toàn bộ JDK ... – Alfonso

+0

+1 để đề cập đến JLS. Nó không chỉ là một sự gian lận của việc thực hiện trình biên dịch. – Antimony