Câu hỏi 1:
Tại sao đoạn mã sau biên dịch mà không có câu lệnh return?
public int a()
{
while(true);
}
Điều này được bao phủ bởi JLS §8.4.7 :
Nếu một phương thức được khai báo là có kiểu trả về (§8.4.5), thì lỗi thời gian biên dịch xảy ra nếu phần thân của phương thức có thể hoàn thành bình thường (§14.1).
Nói cách khác, một phương thức có kiểu trả về chỉ phải trả về bằng cách sử dụng câu lệnh return cung cấp giá trị trả về; phương pháp này không được phép "thả ra khỏi phần cuối của cơ thể". Xem §14.17 để biết các quy tắc chính xác về câu lệnh trả về trong phần thân phương thức.
Phương thức có thể có kiểu trả về và không chứa câu lệnh trả về. Đây là một ví dụ:
class DizzyDean {
int pitch() { throw new RuntimeException("90 mph?!"); }
}
Vì trình biên dịch biết rằng vòng lặp sẽ không bao giờ chấm dứt ( true
tất nhiên luôn luôn đúng), nên nó biết hàm không thể "trả lại bình thường" (thả ra khỏi phần cuối của cơ thể), và do đó không sao cả return
.
Câu hỏi 2:
Mặt khác, tại sao đoạn mã sau lại biên dịch,
public int a()
{
while(0 == 0);
}
mặc dù sau đây không.
public int a(int b)
{
while(b == b);
}
Trong 0 == 0
trường hợp, trình biên dịch biết rằng vòng lặp sẽ không bao giờ kết thúc (điều đó 0 == 0
sẽ luôn đúng). Nhưng nó không biết rằng cho b == b
.
Tại sao không?
Trình biên dịch hiểu các biểu thức hằng (§15.28) . Trích dẫn §15.2 - Các hình thức biểu đạt (vì kỳ lạ câu này không nằm trong §15.28) :
Một số biểu thức có một giá trị có thể được xác định tại thời điểm biên dịch. Đây là các biểu thức không đổi (§15.28).
Trong b == b
ví dụ của bạn , vì có một biến liên quan, nó không phải là biểu thức hằng và không được chỉ định để được xác định tại thời điểm biên dịch. Chúng ta có thể thấy rằng nó luôn luôn đúng trong trường hợp này (mặc dù nếu b
là double
, như QBrute đã chỉ ra , chúng ta có thể dễ dàng bị đánh lừa Double.NaN
, không phải==
là chính nó ), nhưng JLS chỉ xác định rằng các biểu thức không đổi được xác định tại thời điểm biên dịch , nó không cho phép trình biên dịch thử đánh giá các biểu thức không hằng. bayou.io nêu lên một điểm tốt cho lý do tại sao không: Nếu bạn bắt đầu đi vào con đường cố gắng xác định các biểu thức liên quan đến các biến tại thời gian biên dịch, bạn sẽ dừng ở đâu? b == b
là hiển nhiên (er, cho khôngNaN
giá trị), nhưng những gì về a + b == b + a
? Hay là (a + b) * 2 == a * 2 + b * 2
? Vẽ đường tại hằng số có ý nghĩa.
Vì vậy, vì nó không "xác định" biểu thức, trình biên dịch không biết rằng vòng lặp sẽ không bao giờ chấm dứt, vì vậy nó nghĩ rằng phương thức có thể trở lại bình thường - điều mà nó không được phép thực hiện, bởi vì nó bắt buộc phải sử dụng return
. Vì vậy, nó phàn nàn về việc thiếu a return
.