Đây sẽ là một câu trả lời mang tính khái niệm về lý do tại sao những cảnh báo này có thể tồn tại ngay cả với các phương pháp thử tài nguyên. Thật không may, đó không phải là loại giải pháp dễ dàng mà bạn có thể hy vọng đạt được.
Khôi phục lỗi không thể
finally
mô hình một luồng kiểm soát sau giao dịch được thực hiện bất kể giao dịch thành công hay thất bại.
Trong trường hợp thất bại, finally
nắm bắt logic được thực thi ở giữa khi khôi phục từ một lỗi, trước khi nó được khôi phục hoàn toàn (trước khi chúng ta catch
đến đích).
Hãy tưởng tượng vấn đề khái niệm mà nó đưa ra để gặp lỗi ở giữa khi khôi phục từ một lỗi.
Hãy tưởng tượng một máy chủ cơ sở dữ liệu nơi chúng tôi đang cố gắng thực hiện một giao dịch và nó đã thất bại nửa chừng (giả sử máy chủ hết bộ nhớ ở giữa). Bây giờ máy chủ muốn khôi phục giao dịch đến một điểm như không có gì xảy ra. Tuy nhiên, hãy tưởng tượng nó gặp phải một lỗi khác trong quá trình quay trở lại. Bây giờ chúng tôi cuối cùng đã có một giao dịch nửa cam kết với cơ sở dữ liệu - tính nguyên tử và bản chất không thể chia tách của giao dịch hiện đã bị phá vỡ và tính toàn vẹn của cơ sở dữ liệu sẽ bị xâm phạm.
Vấn đề khái niệm này tồn tại trong bất kỳ ngôn ngữ nào liên quan đến lỗi cho dù đó là C với việc truyền mã lỗi thủ công hay C ++ với các ngoại lệ và hàm hủy hoặc Java có ngoại lệ và finally
.
finally
không thể thất bại trong các ngôn ngữ cung cấp nó theo cùng một cách phá hủy không thể thất bại trong C ++ trong quá trình gặp ngoại lệ.
Cách duy nhất để tránh vấn đề khó khăn và khái niệm này là đảm bảo rằng quá trình khôi phục giao dịch và giải phóng tài nguyên ở giữa không thể gặp phải ngoại lệ / lỗi đệ quy.
Vì vậy, thiết kế an toàn duy nhất ở đây là một thiết kế writer.close()
không thể thất bại. Thường có những cách trong thiết kế để tránh các tình huống trong đó những thứ như vậy có thể thất bại ở giữa phục hồi, khiến nó không thể.
Thật không may, cách duy nhất - phục hồi lỗi không thể thất bại. Cách dễ nhất để đảm bảo điều này là làm cho các loại chức năng "giải phóng tài nguyên" và "tác dụng phụ ngược" không có khả năng thất bại. Thật không dễ dàng - phục hồi lỗi thích hợp là khó và cũng không may khó kiểm tra. Nhưng cách để đạt được nó là đảm bảo rằng bất kỳ chức năng nào "phá hủy", "đóng", "tắt máy", "quay lại", v.v. không thể gặp phải lỗi bên ngoài trong quy trình, vì các chức năng đó thường sẽ cần phải được gọi ở giữa phục hồi từ một lỗi hiện có.
Ví dụ: Ghi nhật ký
Giả sử bạn muốn đăng nhập nội dung trong một finally
khối. Điều này thường sẽ là một vấn đề lớn trừ khi đăng nhập không thể thất bại . Ghi nhật ký gần như chắc chắn có thể thất bại, vì nó có thể muốn nối thêm dữ liệu vào tệp và điều đó có thể dễ dàng tìm thấy nhiều lý do để thất bại.
Vì vậy, giải pháp ở đây là làm cho nó để bất kỳ chức năng ghi nhật ký nào được sử dụng trong finally
các khối không thể ném tới người gọi (nó có thể thất bại, nhưng nó sẽ không ném). Làm thế nào chúng ta có thể làm điều đó? Nếu ngôn ngữ của bạn cho phép ném trong bối cảnh cuối cùng với điều kiện là có một khối thử / bắt được lồng nhau, đó sẽ là một cách để tránh ném vào người gọi bằng cách nuốt các ngoại lệ và biến chúng thành mã lỗi, ví dụ: Có thể ghi nhật ký riêng quá trình hoặc luồng có thể bị lỗi riêng và bên ngoài ngăn xếp lỗi khôi phục lỗi hiện có. Miễn là bạn có thể giao tiếp với quá trình đó mà không có khả năng gặp phải lỗi, điều đó cũng sẽ là ngoại lệ, vì vấn đề an toàn chỉ tồn tại trong kịch bản này nếu chúng ta đệ quy từ trong cùng một luồng.
Trong trường hợp này, chúng ta có thể thoát khỏi lỗi đăng nhập với điều kiện là nó không ném vì không đăng nhập và không làm gì cả trên thế giới (nó không rò rỉ bất kỳ tài nguyên nào hoặc không quay lại tác dụng phụ, ví dụ).
Dù sao, tôi chắc chắn rằng bạn đã có thể bắt đầu tưởng tượng mức độ khó khăn đến mức nào để thực sự tạo ra một phần mềm ngoại lệ - an toàn. Có thể không cần thiết phải tìm kiếm điều này ở mức độ đầy đủ nhất trong tất cả trừ phần mềm quan trọng nhất. Nhưng đáng lưu ý về cách thực sự đạt được sự an toàn ngoại lệ, vì ngay cả các tác giả thư viện có mục đích rất chung cũng thường dò dẫm ở đây và phá hỏng toàn bộ ngoại lệ - an toàn cho ứng dụng của bạn khi sử dụng thư viện.
Một sốFileWriter
Nếu SomeFileWriter
có thể ném vào bên trong close
, thì tôi sẽ nói rằng nó thường không tương thích với xử lý ngoại lệ, trừ khi bạn không bao giờ cố gắng đóng nó trong bối cảnh liên quan đến việc khôi phục từ một ngoại lệ hiện có. Nếu mã cho nó nằm ngoài tầm kiểm soát của bạn, chúng tôi có thể là SOL nhưng đáng để thông báo cho các tác giả về vấn đề an toàn ngoại lệ trắng trợn này. Nếu nó nằm trong tầm kiểm soát của bạn, khuyến nghị chính của tôi là đảm bảo rằng việc đóng nó không thể xảy ra bằng bất kỳ phương tiện nào cần thiết.
Hãy tưởng tượng nếu một hệ điều hành thực sự có thể không đóng tệp. Bây giờ bất kỳ chương trình nào cố gắng đóng một tệp khi tắt sẽ không tắt được . Chúng ta phải làm gì bây giờ, chỉ cần mở ứng dụng và trong tình trạng lấp lửng (có thể là không), chỉ cần rò rỉ tài nguyên tệp và bỏ qua vấn đề (có thể ổn nếu nó không quá quan trọng)? Thiết kế an toàn nhất: làm cho nó không thể đóng tệp.