2013-03-04 47 views
5

Giả sử tôi có đoạn mã sau:Làm thế nào để kết hợp khai thác gỗ với một chuỗi xử lý ngoại lệ?

void foo() { 
    /* ... */ 
    try { 
     bar(param1); 
    } catch (MyException e) { 
     /* ??? */ 
    } 
} 

void bar(Object param1) throws MyException { 
    /* ... */ 
    try { 
     baz(param2); 
    } catch (MyException e) { 
     /* ??? */ 
    } 
} 

void baz(Object param2) throws MyException { 
    /* ... */ 
    if (itsAllATerribleMistakeOhNo) { 
     /* ??? */ 
     throw new MyException("oops, error."); 
    } 
} 

Tôi đang tự hỏi ở đâu và làm thế nào tôi nên đăng nhập lỗi.

  • Trường hợp xảy ra lỗi, bên dưới, trong baz(), tôi biết chính xác thao tác nào đã bị lỗi và có thể ghi lại sự thật đó.
  • Ở trên cùng, tôi có ngữ cảnh chung nhất (ví dụ: IP của kết nối trong khi xử lý chúng tôi gặp phải lỗi này.)
  • Trên đường đi, tôi có thể có một số ngữ cảnh không được biết ở trên cùng hoặc ở phía dưới.

Một biến chứng khác là lỗi ở phía dưới có thể không thực sự được coi là lỗi khi bạn nhìn vào nó từ trên cùng (ví dụ: tra cứu thứ gì đó trong cơ sở dữ liệu không thành công; có thể chọn logger.WARN() thay vì logger.ERROR().

Vì vậy, ở trên tôi đã mô tả 3 vị trí (dưới cùng, trên cùng và trên đường đi) - nhưng nó không chỉ là câu hỏi về nơi đăng nhập, mà còn là những gì để ném lên. Ở mọi cấp độ ở giữa, bạn có các tùy chọn 2x2:

  • Log/Không log nhắn
  • Ném ngoại lệ ban đầu/quấn ngoại lệ trong một ngoại lệ mới với thông điệp nói thêm.

Thực tiễn tốt nhất hoặc một số sự khôn ngoan thông thường về những lựa chọn phức tạp này là gì?

Lưu ý: Tôi không hỏi về việc xử lý lỗi/sử dụng ngoại lệ nói chung, chỉ là về tình trạng khó xử được mô tả ở trên.

Trả lời

2

Một số ý kiến ​​cho rằng tôi có xu hướng làm theo:

Link for some best practices

1) Trace ngoại lệ, nơi nó xảy ra. Là điểm mà ngoại lệ xảy ra nếu lớp hoặc API biết ngữ cảnh trong đó ngoại lệ xảy ra sau đó truy tìm và cung cấp nhật ký thích hợp là tốt hơn. Nhưng nếu API không thể xử lý hoặc nhận xét về ngữ cảnh chính xác thì API sẽ không ghi lại sự kiện và để nó trên người gọi.

2) Bao gồm các ngoại lệ: Khi có nhiều ngoại lệ có thể được ném và tất cả ngoại lệ tạo thành một nhóm tương tự (SQLException) cung cấp ngoại lệ duy nhất và cho phép bạn trích xuất thông tin nếu cần. Nếu không thì sẽ có một vụ nổ ngoại lệ mà người gọi cần phải xử lý.

3) Re-Throwing exception: Nếu API ghi lại ngoại lệ và người dùng có thể thực hiện một số hành động trên đó thì ngoại lệ PHẢI được rethrown để báo cho người dùng biết rằng một số điều kiện lỗi đã xảy ra.

4) Nguyên nhân ngoại lệ thích hợp: Thông báo ngoại lệ không được quá cao để người gọi hiểu, bản thân thông báo sẽ hướng dẫn người dùng hiểu lý do cơ bản của ngoại lệ.

UPDATE: Exception Management in Java

+0

Giới thiệu về điểm của bạn 1: Bạn chỉ nên ghi nhật ký tại 1 điểm dọc theo chuỗi cuộc gọi. Bạn có thể giải thích tại sao bạn nghĩ điều này là tốt nhất? Về điểm 2: gói và sử dụng một cây phân lớp ngoại lệ là hai thứ khác nhau ... Về điểm 4: Điểm tốt nhưng không liên quan đến tình trạng khó xử của tôi. – einpoklum

+0

Trong trường hợp của thông điệp dấu vết, truy tìm tại các điểm ngoại lệ xảy ra chứng tỏ hữu ích cho các nhà phát triển. Khi bạn cho biết chuỗi thêm vào lý do ngoại lệ. Sau đó, theo tôi, bạn nên tạo riêng biệt kiểm tra ngoại lệ để chính xác chỉ ra lý do. Nếu đó là một lỗi lập trình viên hoặc lập trình thì việc ném ngoại lệ thời gian chạy là tốt hơn. Ví dụ 'DBConnectivityNotAvailable' có thể được kiểm tra ngoại lệ. Bạn có thể đưa ra một ví dụ về trường hợp của bạn, nơi bạn đang bối rối? Tôi có nghĩa là nó phụ thuộc vào từng trường hợp để sử dụng chiến lược nào để khai thác gỗ. –

+0

Mỏ là một trường hợp phức tạp của một số trường hợp ngoại lệ đã kiểm tra hiện tại và một số ngoại lệ thời gian chạy tiềm ẩn, hiện tại tôi có một khối chặn ở đầu chuỗi cuộc gọi và các thanh ghi thường xuyên dọc theo chuỗi. Ngoài ra còn có các vấn đề ERROR-vs-WARN, trong đó phần dưới cùng của chuỗi không thể biết liệu có cái gì đó là L ERI hay không. – einpoklum

1

Khi tôi ném ngoại lệ vào mã của mình, tôi thường không ghi nhật ký bất kỳ thứ gì. Ngoại lệ là đủ thông tin. Ngoại lệ duy nhất cho điều này là, khi tôi ở biên giới của hệ thống, có nghĩa là, khi ngoại lệ sẽ rời khỏi ranh giới của hệ thống của tôi, thì tôi đăng nhập vì tôi không chắc chắn hệ thống khác sẽ làm gì với lỗi.

Khi tôi xử lý ngoại lệ, tôi ghi lại chúng khi tôi chủ động xử lý chúng, điều đó có nghĩa là khi tôi đang ở trong một điều khoản nắm bắt làm điều gì đó nhiều hơn thì chỉ cần sửa lại ngoại lệ. Thông thường điều này là khá ở đầu, nhưng điều này phụ thuộc vào tình hình.

+0

nhưng còn về: (1) Khi bạn xử lý một phần điều gì trên đường đi? (2) Thông tin ngữ cảnh khác nhau có sẵn ở những nơi khác nhau trong chuỗi cuộc gọi? – einpoklum

+0

Tôi có những tình huống đó ít khi xảy ra. Giống như tôi phải chuyển đổi một ngoại lệ vì thay đổi ngữ cảnh trước khi làm lại nó. Điều này sau đó phụ thuộc rất nhiều vào tình hình nhưng thường là một mục nhập nhật ký trên một mức WARN nên là một ý tưởng tốt. – Matthias

+0

Đối với trường hợp (2) Điều này sẽ ảnh hưởng đến sự giải trừ của bạn nếu bạn muốn xử lý ngoại lệ hoặc chỉ để tuyên bố nó được ném bằng phương pháp này. Nếu bối cảnh là đủ để xử lý nó, đó là tốt, nếu không chỉ để cho các cấp cao hơn của ngăn xếp cuộc gọi xử lý mọi thứ. – Matthias

1

Khi ném một ngoại lệ ở giai đoạn thử nghiệm, bạn nên nhớ:

  • Giữ thông điệp ngoại lệ càng rõ ràng càng tốt. Dấu vết ngăn xếp có thể gây nhầm lẫn tại thời điểm tốt nhất để đảm bảo rằng những gì bạn đang đọc, ít nhất, có ý nghĩa với bạn.
  • Đảm bảo rằng ngoại lệ có liên quan đến sự kiện. Nếu người dùng nhập sai giá trị và bạn ném một NullPointerException, mã của bạn là phi logic và mất giá trị của nó.
  • Đảm bảo rằng nó có nhiều thông tin VỀ SỰ KIỆN càng tốt. Đó là, giữ cho thông điệp có liên quan.Nếu cuộc gọi cơ sở dữ liệu bị lỗi, hãy in chuỗi kết nối vào cơ sở dữ liệu và truy vấn SQL đã thử. Trạng thái của mọi biến hiện đang được sử dụng là không cần thiết.
  • Không quấy rầy. Nó rất hấp dẫn để gõ vào thuật ngữ kỹ thuật để làm cho nó trông giống như bạn đang hack vào ma trận. Nó không giúp bạn trong một tình huống căng thẳng, và nó chắc chắn không giúp bất cứ ai khác sử dụng mã của bạn. Từ tiếng Anh đơn giản luôn thích hợp hơn.
  • Cuối cùng, KHÔNG BAO GIỜ KHÁM PHÁ. Luôn đảm bảo bạn xử lý ngoại lệ và bạn đang xuất chi tiết theo cách nào đó, tuân theo các quy tắc tôi đã nêu ở trên.
+0

Đây là tất cả lời khuyên tốt về cách làm việc với ngoại lệ, nhưng không chính xác câu hỏi của tôi là gì ... – einpoklum

2

Khi nói đến việc khai thác gỗ, tôi muốn giữ tất cả các đăng nhập của tôi ở phía trên cùng ở ranh giới ứng dụng. Thông thường, tôi sử dụng bộ chặn hoặc bộ lọc để xử lý tất cả việc ghi nhật ký theo cách tổng quát. Theo khái niệm này, tôi có thể đảm bảo rằng mọi thứ được ghi lại một lần và chỉ một lần.

Trong trường hợp này, bạn sẽ đăng nhập vào phương thức foo() hoặc bất kỳ điểm nhập nào vào ứng dụng của bạn (bạn đã đề cập địa chỉ IP, tôi cho rằng chúng ta đang nói về một thùng chứa servlet hoặc máy chủ ứng dụng).

Hơn, bắt ngoại lệ của riêng bạn trong bộ lọc/bộ chặn và ghi lại tùy thuộc vào nhu cầu của bạn. Thêm catch throwable để bắt tất cả các ngoại lệ khác mà bạn không xử lý trong mã của mình và ghi lại chúng dưới dạng lỗi, vì rõ ràng là bạn đã bỏ sót thứ gì đó khác trong dấu vết ngăn xếp.

Khái niệm này yêu cầu một số quy hoạch phía trước. Bạn có thể sẽ sử dụng ApplicationException của riêng bạn để lưu trữ Thông báo Lỗi (Chuỗi) cùng với một số mức độ nghiêm trọng (có thể trong một Enum). Bạn cần điều này để chọn mức nhật ký chính xác khi bạn thực hiện ghi nhật ký thực.

Điều này phù hợp với tất cả các trường hợp và có lợi thế là tất cả việc ghi nhật ký diễn ra chính xác một lần. Tuy nhiên, có một trường hợp bạn vẫn cần đăng nhập vào mã của mình: nếu bạn hoàn toàn có thể gặp lỗi ở đâu đó trong mã của mình (có nghĩa là ngoại lệ xảy ra và bạn có thể làm điều gì đó cho phép bạn tiếp tục làm việc mà không cần phải ném lại) một ngoại lệ). Vì bạn không ném một ngoại lệ, không có gì sẽ được ghi lại bằng cách khác.

Nói tóm lại:

  • Log ở vị trí trên cùng một cách tổng quát, tốt nhất là sử dụng một chặn hoặc lọc.
  • Bọc ngoại lệ bên trong Ứng dụng của riêng bạnXuất hiện và thêm mức độ nghiêm trọng cộng với những thứ quan tâm khác để đăng nhập vào ứng dụng của bạn.