2012-01-05 34 views
9

Đây là mã mà tôi đã viết.tại sao khối catch đưa ra lỗi với biến không được khởi tạo trong Java

int num; 
try { 
    num=100; 
    DoSomething(); 
    System.out.println(num); 
} catch(Exception e) { 
    DoSomething1(); 
} finally{ 
    DoSomething2(); 
} 
System.out.println(num); // Error Line 

Tôi gặp lỗi 'Biến số địa phương có thể chưa được khởi tạo' trên dòng lỗi mà tôi đã đề cập. Khi loại bỏ khối catch, lỗi sẽ biến mất. Có gì sai ở đây? Tôi đang làm điều gì đó không chính xác?

+0

Có liên quan, chắc chắn. :) –

Trả lời

10

Nếu có ngoại lệ được ném vào khối try của bạn, thì biến số num thực sự có thể chưa được khởi tạo. Nếu bạn bao gồm khối catch, thì việc thực thi có thể tiếp tục đến dòng lỗi bất kể, và do đó trình biên dịch báo cáo lỗi bạn nêu.

Nếu bạn xóa khối catch, khi đó việc thực hiện sẽ chỉ đạt đến "đường lỗi" nếu không có ngoại lệ và trong trường hợp này, biến sẽ được khởi tạo trong số try.

(tôi giả sử bạn đã biết về sự cần thiết phải intialise biến địa phương trước khi sử dụng chúng, và đã tập trung vào những gì bạn nhận thấy với khối catch ...)

+0

Có, tôi nhận thức được điều đó, điều làm cho nó thú vị là việc loại bỏ khối catch khiến lỗi biến mất. – gizgok

+0

@gizgok David đã trả lời câu hỏi này khi ông nói: "Nếu bạn loại bỏ khối catch, thì việc thực hiện sẽ chỉ đạt đến" dòng lỗi "nếu không có ngoại lệ, và trong trường hợp này, biến sẽ được khởi tạo trong lần thử. " +1 btw –

+0

Yup. Hy vọng lời giải thích phù hợp với bạn. –

2

Biến cục bộ trong Java không được tự động khởi tạo. Vì vậy, bạn cần phải khởi tạo nó trước khi sử dụng chúng.

int num=0; 
try 
{ 
    .. 
} 
... 

Fore biết thêm đọc - Definite Assignment (JLS - 16.2.15 try Statements)

+1

Nhưng ông IS khởi tạo nó tại 'num = 100;' Đường dẫn thực hiện cũng không có nhánh (không có câu lệnh 'if else'). Vì vậy, java nên biết rằng 'num' là' 100'. –

+1

@Rosdi - Đó là bên trong khối thử. – adatapost

+0

Tôi biết về phần khởi tạo, tôi quan tâm hơn đến cách loại bỏ khối catch dẫn đến không có lỗi. – gizgok

0

Vấn đề là rằng num không initializated, int num = -1; Và lỗi sẽ biến mất;)

+0

Nhưng phép gán 'num = 100' được thực hiện trước khi bất kỳ ngoại lệ nào có thể được ném ra. Vì vậy, khối catch sẽ luôn luôn được thực thi * sau * phép gán. –

+0

Như @AVD đã nói "Các biến cục bộ trong Java không được tự động khởi tạo" – DVD

+0

Có, nhưng biến ** sẽ ** được khởi tạo trước khi nó được truy cập. –

3

xử lý ngoại lệ có thể gây nhầm lẫn cho trình biên dịch. Trong trường hợp này, bạn biết rằng một ngoại lệ không thể được ném TRƯỚC KHI biến số num được đặt, nhưng trình biên dịch không biết điều này.

Trình biên dịch cho rằng ngoại lệ có thể được ném trước num đã được đặt trong trường hợp này num sẽ không được khởi chạy khi bạn cố gắng in bên ngoài khối try-catch.

+1

Bạn * không * biết rằng nhiệm vụ không thể chạy. Xem ví dụ của @ FabianBarney cho một trường hợp. –

3

Trong Java, bạn phải khởi động các vars cục bộ. Điều này không được đảm bảo khi bạn có các khối catch này vì một ngoại lệ có thể được ném trước khi init var cục bộ trong khối try và bạn không khởi động var trong khối catch. Do đó, var cục bộ có thể không được khởi tạo sau khối try-catch-finally.

Khi bạn loại bỏ khối catch thì var được khởi tạo sau khi thử hoặc một ngoại lệ được ném và mã sau khi try-block không bao giờ được thực thi.

Bạn đã sau khả năng để sửa lỗi này:

  • init var trước khi thử khối
  • init var trong thử khối và bắt khối
  • init var trong khối finally
  • init chỉ var trong try-block, nhưng không bắt ngoại lệ

var cục bộ không được đảm bảo khởi tạo ngay cả khi var init là t điều đầu tiên bạn làm trong thử-block.Ví dụ, chuỗi được thực thi có thể được dừng lại với Thread.stop(Throwable) sau khi nhập try-block nhưng trước var init. Khi điều này xảy ra thì var không được khởi tạo nhưng bắt cuối cùng được thực thi và đoạn mã sau khi try-catch-finally là tốt.

Dưới đây là một ví dụ cho thấy những gì tôi có nghĩa là:

public static void main(String[] args) throws InterruptedException { 
    Thread thread = new MyThread(); 

    thread.start(); 
    Thread.sleep(100); 
    thread.stop(new Exception()); 
} 

private static class MyThread extends Thread { 

    @Override 
    public void run() { 
     int num = -1; 

     try { 
      Thread.sleep(600); //just to hit the thread at the right point 
      num = 100; 
      System.out.println("blub"); 
     } 
     catch (Exception e) { 
      System.out.println("catch"); 
     } 
     finally { 
      System.out.println("finally"); 
     } 


     System.out.println(num); 
     System.out.println("after all"); 
    } 

} 

Mã này in ra:

catch 
finally 
-1 
after all 
+0

Ví dụ> giải thích – yunandtidus

2

Bạn đã Putten num = 100 bên yout try khối, trình biên dịch giả định rằng một lỗi có thể xảy ra trước khi Đã đạt đến số num = 100. Vì vậy, khi bạn nhập vào trong blob Catch, đối với trình biên dịch, anh ta chỉ thấy int num cung cấp cho bạn lỗi Variable not initialized.

+0

Lỗi nào có thể xảy ra trước khi đạt đến 'num = 100;' line? –

+4

@Rosdi Đối với trình biên dịch, bất kỳ lỗi nào cũng có thể xảy ra. Trồng JVM, Lỗi nội bộ được tạo ra, ... –

1

tôi tình cờ đã viết blog về vấn đề này ngày hôm qua http://vanillajava.blogspot.com/2012/01/odd-case-of-initialization.html

Nói tóm lại, trình biên dịch không biết nếu biến đã được khởi tạo bên trong một try/catch, ngay cả trong trường hợp tầm thường nhất. Vì lý do này, nó phàn nàn biến có thể chưa được khởi tạo.

Điều thú vị là nếu bạn thực hiện biến cuối cùng và cố gắng đặt biến sau khối try/catch, trình biên dịch sẽ phàn nàn nó có thể đã được khởi tạo.

+0

, rất thú vị giới thiệu khía cạnh cuối cùng cho biến. Lý do tại sao điều này xảy ra? Bất kỳ ý tưởng? – gizgok

+0

Bạn không thể đặt biến cuối cùng nếu nó đã được khởi tạo và sau khối try/catch, nó có thể hoặc không thể được khởi tạo. Trình biên dịch chỉ không có ý tưởng. –

+0

Có tà ác với 'Thread.stop (Throwable)' có thể dẫn đến một trạng thái mà var cục bộ thực tế không được khởi tạo trong ví dụ đã cho. –

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