Sự khác biệt giữa thử / bắt / ném và thử / bắt (e) / ném e


103

Sự khác biệt giữa

try { }
catch
{ throw; }

try { }
catch(Exception e)
{ throw e;}

?

Và khi nào tôi nên sử dụng cái này hay cái kia?

Câu trả lời:


151

Các công trình

try { ... }
catch () { ... } /* You can even omit the () here */

try { ... }
catch (Exception e) { ... }

giống nhau ở chỗ cả hai sẽ bắt mọi ngoại lệ được đưa vào bên trong trykhối (và, trừ khi bạn chỉ đơn giản sử dụng điều này để ghi lại các ngoại lệ, nên tránh ). Bây giờ hãy xem những điều này:

try { ... }
catch ()
{
    /* ... */
    throw;
}

try { ... }
catch (Exception e)
{
    /* ... */
    throw;
}

try { ... }
catch (Exception e)
{
    /* ... */
    throw e;
}

Khối try-catch thứ nhất và thứ hai CHÍNH XÁC giống nhau, chúng chỉ đơn giản là ném lại ngoại lệ hiện tại và ngoại lệ đó sẽ giữ nguyên "nguồn" và dấu vết ngăn xếp.

Khối try-catch thứ ba thì khác. Khi nó ném ngoại lệ, nó sẽ thay đổi nguồn và dấu vết ngăn xếp, do đó nó sẽ xuất hiện rằng ngoại lệ đã được ném từ phương thức này, từ chính dòng đó throw etrên phương thức chứa khối try-catch đó.

Bạn nên sử dụng cái nào? Nó thực sự phụ thuộc vào từng trường hợp.

Giả sử bạn có một Personlớp với một .Save()phương thức sẽ lưu nó vào cơ sở dữ liệu. Giả sử rằng ứng dụng của bạn thực thi Person.Save()phương thức ở đâu đó. Nếu DB của bạn từ chối lưu Người, thì .Save()sẽ đưa ra một ngoại lệ. Bạn có nên sử dụng throwhoặcthrow e trong trường hợp này? Vâng, nó phụ thuộc.

Điều tôi thích là làm:

try {
    /* ... */
    person.Save();
}
catch(DBException e) {
    throw new InvalidPersonException(
       "The person has an invalid state and could not be saved!",
       e);
}

Điều này sẽ đặt DBException là "Ngoại lệ bên trong" của ngoại lệ mới hơn được ném. Vì vậy, khi bạn kiểm tra InvalidPersonException này, dấu vết ngăn xếp sẽ chứa thông tin quay lại phương thức Lưu (có thể đủ để bạn giải quyết vấn đề), nhưng bạn vẫn có quyền truy cập vào ngoại lệ ban đầu nếu bạn cần.

Nhận xét cuối cùng, khi bạn đang mong đợi một ngoại lệ, bạn thực sự nên nắm bắt một ngoại lệ cụ thể đó chứ không phải một ngoại lệ chung chung Exception, tức là nếu bạn đang mong đợi một InvalidPersonException, bạn nên thích:

try { ... }
catch (InvalidPersonException e) { ... }

đến

try { ... }
catch (Exception e) { ... }

Chúc may mắn!


34

Đầu tiên bảo tồn dấu vết ngăn xếp trong khi thứ hai đặt lại nó. Điều này có nghĩa là nếu bạn sử dụng cách tiếp cận thứ hai, dấu vết ngăn xếp của ngoại lệ sẽ luôn bắt đầu từ phương pháp này và bạn sẽ mất dấu vết ngoại lệ ban đầu, điều này có thể gây tai hại cho người đọc nhật ký ngoại lệ vì anh ta sẽ không bao giờ tìm ra nguyên nhân ban đầu của ngoại lệ .

Cách tiếp cận thứ hai có thể hữu ích khi bạn muốn thêm thông tin bổ sung vào dấu vết ngăn xếp nhưng nó được sử dụng như thế này:

try
{
    // do something
}
catch (Exception ex)
{
    throw new Exception("Additional information...", ex);
}

Có một bài đăng trên blog thảo luận về sự khác biệt.


Vâng, đó là điều tuyệt vời để biết!
Myles

vậy tại sao sử dụng thứ hai sau đó? tốt hơn là chỉ sử dụng cái đầu tiên?
Karim

1
Điều thứ hai hữu ích khi bạn cần kiểm tra các ngoại lệ cụ thể - OutOfRangeException xuất hiện trong tâm trí - hoặc cần ghi nhật ký thư, v.v. Đầu tiên dường như là một trình xử lý ngoại lệ ký tự đại diện tương tự như thử {} catch (...) {} trong c ++.
3Dave

1
David, điều đó chỉ áp dụng cho phần bắt (Ngoại lệ e) . Và đó là tách biệt throwvs throw e.
Henk Holterman

6

Bạn nên sử dụng

try { }
catch(Exception e)
{ throw }

nếu bạn muốn làm điều gì đó với ngoại lệ trước khi ném lại nó (ghi nhật ký chẳng hạn). Sự cô đơn ném bảo tồn dấu vết ngăn xếp.


và điều gì sẽ xảy ra nếu tôi thay thế "ném" ở đây bằng "ném e"?
Karim

5

Sự khác biệt giữa bắt không tham số và một catch(Exception e)là bạn nhận được một tham chiếu đến ngoại lệ. Từ phiên bản khung 2, các ngoại lệ không được quản lý được bao bọc trong một ngoại lệ được quản lý, do đó, ngoại lệ không tham số không còn hữu ích cho bất cứ điều gì.

Sự khác biệt giữa throw;throw e;là cái đầu tiên được sử dụng để ném lại các ngoại lệ và cái thứ hai được sử dụng để ném một ngoại lệ mới được tạo. Nếu bạn sử dụng cái thứ hai để ném lại một ngoại lệ, nó sẽ coi nó như một ngoại lệ mới và thay thế tất cả thông tin ngăn xếp từ nơi nó được ném ban đầu.

Vì vậy, bạn không nên sử dụng một trong hai lựa chọn thay thế trong câu hỏi. Bạn không nên sử dụng bắt không có tham số và bạn nên sử dụng throw;để ném lại một ngoại lệ.

Ngoài ra, trong hầu hết các trường hợp, bạn nên sử dụng một lớp ngoại lệ cụ thể hơn lớp cơ sở cho tất cả các trường hợp ngoại lệ. Bạn chỉ nên nắm bắt những trường hợp ngoại lệ mà bạn dự đoán.

try {
   ...
} catch (IOException e) {
   ...
   throw;
}

Nếu bạn muốn thêm bất kỳ thông tin nào khi nhập lại ngoại lệ, bạn tạo một ngoại lệ mới với ngoại lệ ban đầu là ngoại lệ bên trong để bảo toàn tất cả thông tin:

try {
   ...
} catch (IOException e) {
   ...
   throw new ApplicationException("Some informative error message", e);
}
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.