PDA

View Full Version : [Q] Khối lệnh finally có tác dụng gì ??



computerboy
05-01-2003, 03:52
Mình là dân mới nghiên cứu Java, xin cho hỏi khối lệnh finally trong phần quản lí và bắt biệt lệ có ý nghĩa quan trọng như thế nào mà Java lại đưa vào ? (trong C++ không có)
Theo như "The Java Tutorial" của Java.Sun thì ..... xét đoạn chương trình sau:

public void writeList() {
PrintWriter out = null;

try {
System.out.println("Entering try statement");
out = new PrintWriter(
new FileWriter("OutFile.txt"));

for (int i = 0; i < size; i++)
out.println("Value at: " + i + " = " + victor.elementAt(i));
} catch (ArrayIndexOutOfBound***ception e) {
System.err.println("Caught ArrayIndexOutOfBound***ception: " +
e.getMessage());
} catch (IOException e) {
System.err.println("Caught IOException: " + e.getMessage());
} finally {
if (out != null) {
System.out.println("Closing PrintWriter");
out.close();
} else {
System.out.println("PrintWriter not open");
}
}
}

và rằng:
"The need for a finally statement is not apparent until you consider the following: how does the PrintWriter in the writeList method get closed if you don't provide an exception handler for the ArrayIndexOutOfBound***ception and an ArrayIndexOutOfBound***ception occurs?"

Nhưng mình lại thấy rằng khối finally hầu như không có chức năng gì ở đây, vì ta có thể thay khối finally bằng "phần thân" của nó, tức là
if (out != null) {
System.out.println("Closing PrintWriter");
out.close();
} else {
System.out.println("PrintWriter not open");
}
là được !??!

Không biết nhân xét của mình có gì không đúng, nhờ các bạn chỉ giùm !!

Zizou
05-01-2003, 08:09
Ý nghĩa của câu chú thích đi kèm mà bạn trích trong câu hỏi vừa rồi là nếu bạn không có cái exception handler cho ArrayIndexOutOfBound***ception (nghĩa là bạn bỏ đi nguyên khối code catch cái exception nói trên), thì sẽ thấy tác dụng rõ rệt của mệnh đề finally . Nghĩa là khi đó nêu bạn thay thế khối code trong finally bằng thân của nó (như bạn đã làm), và một ArrayIndexOutOfBound***ception xuất hiện thì phần code đó không bao giờ đuợc executed (trong truờng hợp này PrintWriter out không được closed )

Nguyên nhân là trong truờng hợp khi bạn access cái Vector victor (bằng elementAt) gây ra một ArrayIndexOutOfBound***ception, khiến cho JVM hoặc là nhảy đến khối code (nếu có) để catch cái exception đó , hoặc là terminate cái thread hiện tại nếu khối code để catch cái exception đó không tồn tại . Ví dụ tôi đưa ra ở trên sẽ rơi vào trường hợp thứ 2. Nghĩa là cái thread hiện tại sẽ terminate mà không thực hiện việc closing PrinterWriter. Nguoc lại nếu bạn dùng mệnh đề finally, thì PrinterWriter sẽ đuợc closed. Đó là vì theo Java, KHỐI CODE TRONG MỆNH ĐỀ FINALLY LUON LUON ĐƯƠC EXECUTED BẤT KỂ KHỐI CODE TRONG MỆNH ĐỀ TRY (HAY CATCH) THOÁT RA NHƯ THẾ NÀO. Để thấy rõ hơn bạn có thể chèn câu lệnh "return; hay break;" vào trong khôi code của try, thì thấy JVM vẫn tiếp tục thực hiện khối code trong finally.

Cũng cần nói rõ thêm, trong cái ví dụ bạn đưa ra, lập trình viên râ't dễ quên không có đoạn code để catch cái ArrayIndexOutOfBound***ception bởi vì nó là Runtime exception nên những java compiler thông thường không thể nhận diện đuợc và báo lại cho lập trình viên . Do đó finally rất hữu dụng trong truờng hợp này vì nó bảo đảm rằng PrinterWriter luôn luôn được close bất kể truờng hợp nào xảy ra

Thân,

computerboy
05-01-2003, 18:50
Cám ơn Zizou đã giải thích giùm mình. Nhưng mình vẫn còn thắc mắc là.... tài liệu của Sun bảo rằng:
"After the finally block has completed executing, the program continues with the first statement after the finally block. "
Vậy thì mình có thể không cần phải close printer trong khối finally mà chỉ cần để trống khối finally đó, rồi đưa phần
if (out != null) {
System.out.println("Closing PrintWriter");
out.close();
} else {
System.out.println("PrintWriter not open");
}
ra sau khối finally trống đó. Như thế, chương trình vẫn chạy tốt chứ ?!

Zizou
06-01-2003, 10:38
Nếu giữ nguyên đđdoan code bạn dua ra làm ví dụ thì viec di chuyển thân của finally ra ngoài hay vào trong deu cho kết quả như nhau (i.e vẫn cha.y tô't ;) ).

Tuy nhiên nêu bạn xóa cái handler cho ArrayIndexOutOfBoundException và thử tạo một exception kiểu do (e.g. victor.elementAt(victor.size))), bạn sẽ thấy sự khác biệt do finally clause tạo nên.

Thân,