Làm thế nào để JVM xử lý một ngoại lệ được ném bởi phương thức chính?


10

Tôi hiểu các trường hợp ngoại lệ, ném chúng, xử lý chúng và truyền chúng đến một phương thức thấp hơn trong ngăn xếp cuộc gọi (nghĩa là throws).

Điều tôi không hiểu là đây:

public static void main(String[] args) throws Exception {
    ...
}

Bây giờ, tôi giả sử rằng trong trường hợp mainném một Exception, JVM sẽ xử lý nó (đúng không?). Nếu đó là trường hợp, thì câu hỏi của tôi là:

Làm thế nào để JVM xử lý các ngoại lệ được ném bởi main? Nó làm gì?

Câu trả lời:


19

Bạn có thể nghĩ rằng public static void mainphương thức trong Java hoặc mainhàm trong C là điểm vào thực sự của chương trình của bạn - nhưng không phải vậy. Tất cả các ngôn ngữ cấp cao (bao gồm C) có thời gian chạy ngôn ngữ khởi tạo chương trình và sau đó chuyển luồng điều khiển đến điểm vào. Trong trường hợp của Java, việc khởi tạo sẽ bao gồm:

  • thiết lập JVM
  • tải các lớp yêu cầu
  • chạy các khối khởi tạo tĩnh. Điều này có thể thực thi mã do người dùng xác định trước khi mainđược gọi. Những khối này không được phép ném ngoại lệ.

Có nhiều cách khác nhau để thực hiện xử lý ngoại lệ, nhưng với mục đích của câu hỏi này, tất cả chúng có thể được xem như một hộp đen. Tuy nhiên, điều quan trọng là thời gian chạy ngôn ngữ phải luôn cung cấp trình xử lý ngoại lệ ngoài cùng để nắm bắt tất cả các ngoại lệ không bị bắt bởi mã người dùng. Trình xử lý ngoại lệ này thường sẽ in ra một dấu vết ngăn xếp, tắt chương trình theo thứ tự và thoát với mã lỗi. Tắt chương trình một cách thích hợp bao gồm phá hủy biểu đồ đối tượng, gọi trình hoàn thiện và giải phóng các tài nguyên như bộ nhớ, xử lý tệp hoặc kết nối mạng.

Đối với mục đích minh họa, bạn có thể chụp ảnh thời gian chạy gói tất cả mã trong một lần thử khổng lồ trông giống như

try {
    loadClasses();
    runInitializers();
    main(argv);
    System.exit(0);
} catch (Throwable e) {
    e.printStackTrace();
    System.exit(-1);
}

ngoại trừ việc ngôn ngữ không thực sự thực thi mã như thế này là không cần thiết. Các ngữ nghĩa tương tự có thể được thực hiện trong mã cho throw(hoặc tương đương) để tìm kiếm trình xử lý ngoại lệ áp dụng đầu tiên.


9

Tất cả các mã Java chạy trong ngữ cảnh của một luồng . JavaDoc được liên kết giải thích các tiêu chí xử lý và thoát lỗi, nhưng đây là ý chính của nó:

  • JVM tự quay tròn và chuẩn bị môi trường thực thi.
  • JVM tạo ra một luồng sẽ chạy main()phương thức bằng cách sử dụng bất kỳ tham số dòng lệnh nào được áp dụng.
  • JVM thiết lập một trình xử lý ngoại lệ chưa được mặc định in ra ngoại lệ cho lỗi tiêu chuẩn và chấm dứt.
  • JVM thực thi luồng.

Trong trường hợp ngoại lệ chưa được phát hiện, chương trình sẽ thực sự chết theo mục thứ ba ở trên. Hành vi này được chỉ định thêm trong Đặc tả ngôn ngữ Java, Phần 11.3


thông tin bổ sung

Những người khác đã đề cập đến các khối tĩnh và cách họ thực hiện trước đó main(). Tuy nhiên, điều này đòi hỏi một chút giải thích để hiểu chính xác.

Khi tải một lớp, trình nạp lớp phải khởi tạo tất cả static finaltrạng thái và chạy tất cả staticcác khối trước khi lớp có thể được sử dụng, để bao gồm các thể hiện khởi tạo của lớp (sang một bên: tạo một lớp Java trong đó hằng số lớp được khởi tạo trong một khối tĩnh sau khi tạo thể hiện của lớp và hàm tạo tham chiếu hằng số. Boom!). Tuy nhiên, tất cả điều này xảy ra trong logic trình nạp lớp trước khi bất kỳ mã nào có thể tham chiếu lớp . Hơn nữa, lớp được tải trong bất kỳ chủ đề nào tham chiếu lớp.

Điều này có nghĩa là nếu lớp chứa main()tham chiếu một lớp khác (ví dụ: hằng lớp) thì lớp đó phải được tải trước khi main()thực thi để bao gồm các khối tĩnh của nó. Mặt khác, các khối tĩnh được thực hiện như trên. Nếu lớp không tải, thì lớp chứa main()cũng sẽ không tải và chương trình sẽ kết thúc.

Một FYI khác: khối tĩnh có thể ném. Errorsđược ném như vốn có. Exceptionsbị cấm (lỗi thời gian biên dịch). RuntimeExceptionsđược gói trong ExceptionInitializerError . Chúng được xử lý theo trình xử lý ngoại lệ chưa được xử lý, thông thường sẽ giết luồng hoặc ứng dụng (luồng chính) trừ khi bạn cẩn thận bọc tham chiếu lớp (và tải) trong một try- catch.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.