Tôi nghĩ về nó và không thể đưa ra một ví dụ. Tại sao ai đó muốn bắt một ngoại lệ và không làm gì về nó? Bạn có thể đưa ra một ví dụ không? Có lẽ nó chỉ là thứ không bao giờ nên làm.
Tôi nghĩ về nó và không thể đưa ra một ví dụ. Tại sao ai đó muốn bắt một ngoại lệ và không làm gì về nó? Bạn có thể đưa ra một ví dụ không? Có lẽ nó chỉ là thứ không bao giờ nên làm.
Câu trả lời:
Tôi làm điều đó mọi lúc với những thứ như lỗi chuyển đổi trong D:
import std.conv, std.stdio, std.exception;
void main(string[] args) {
enforce(args.length > 1, "Usage: foo.exe filename");
double[] nums;
// Process a text file with one number per line into an array of doubles,
// ignoring any malformed lines.
foreach(line; File(args[1]).byLine()) {
try {
nums ~= to!double(line);
} catch(ConvError) {
// Ignore malformed lines.
}
}
// Do stuff with nums.
}
Điều đó nói rằng, tôi nghĩ rằng tất cả các khối bắt phải có một cái gì đó trong chúng, ngay cả khi đó chỉ là một nhận xét giải thích lý do tại sao bạn bỏ qua ngoại lệ.
Chỉnh sửa: Tôi cũng muốn nhấn mạnh rằng, nếu bạn định làm điều gì đó như thế này, bạn nên cẩn thận chỉ bắt ngoại lệ cụ thể mà bạn muốn bỏ qua. Làm một người già đơn giản catch {}
hầu như luôn luôn là một điều xấu.
Một ví dụ mà tôi nghĩ là ổn khi chỉ nuốt ngoại lệ mà không làm gì cả, thậm chí ghi nhật ký ngoại lệ, nằm trong chính mã đăng nhập.
Nếu bạn đã cố gắng đăng nhập một cái gì đó và có ngoại lệ, bạn không thể làm gì nhiều về nó:
Điều đó khiến bạn có tùy chọn "ít nhất là xấu xa" khi lặng lẽ nuốt nó, cho phép ứng dụng tiếp tục thực hiện công việc chính của mình, nhưng ảnh hưởng đến khả năng khắc phục sự cố.
Nếu một ngoại lệ được ném bởi một thao tác là tùy chọn, thì có thể không có gì để làm. Nó có thể không hữu ích để đăng nhập nó. Trong trường hợp đó, bạn có thể chỉ muốn bắt nó và không làm gì cả.
Nếu bạn đang làm điều này, bao gồm một nhận xét. Luôn bình luận bất cứ điều gì trông giống như một lỗi (lỗi trong một switch
câu lệnh, catch
khối trống , bài tập trong một điều kiện).
Bạn có thể lập luận rằng đây không phải là cách sử dụng ngoại lệ thích hợp, nhưng đó là một câu hỏi khác.
catch
Khối trống là một mùi mã trong hầu hết các ngôn ngữ. Ý tưởng chính là sử dụng các ngoại lệ cho các tình huống đặc biệt và không sử dụng chúng để kiểm soát logic. Tất cả các ngoại lệ phải được xử lý ở đâu đó.
Do hậu quả của việc thực hiện phương pháp này, khi bạn lập trình một lớp ứng dụng cụ thể, bạn có một số lựa chọn:
Điều này không thực sự để lại bất kỳ phòng cho không làm gì, catch
khối trống .
EDITED TO ADD : giả sử bạn đang lập trình bằng một ngôn ngữ trong đó ném ngoại lệ là cách thông thường để kiểm soát logic chương trình (một trong những lựa chọn thay thế goto
). Sau đó, một catch
khối trống trong một chương trình được viết bằng ngôn ngữ này rất giống với một else
khối trống trong ngôn ngữ truyền thống (hoặc không có else
khối nào cả). Tuy nhiên, tôi tin rằng đây không phải là phong cách lập trình được đề xuất bởi các cộng đồng phát triển C #, Java hoặc C ++.
Trong một số trường hợp, Java yêu cầu bạn xử lý một ngoại lệ có thể, trong mọi trường hợp hoàn toàn không xảy ra. Hãy xem xét mã này:
try {
bytes[] hw = "Hello World".getBytes("UTF-8");
}
catch(UnsupportedCodingException e) {
}
Mọi triển khai của nền tảng Java là bắt buộc để hỗ trợ các bộ ký tự chuẩn sau đây.
...
UTF-8
Không phá vỡ nền tảng Java của bạn, đơn giản là không có cách nào để gây ra ngoại lệ này. Vậy tại sao phải xử lý nó? Nhưng bạn không thể đơn giản sử dụng mệnh đề try-Catch-.
throw new Error(e)
chỉ để chắc chắn rằng tôi đã không bỏ lỡ bất cứ điều gì (hoặc báo cáo nền tảng thực sự bị hỏng).
Theo nguyên tắc chung, không. Bạn có thể muốn ném ngoại lệ lên ngăn xếp, hoặc ghi lại những gì đã xảy ra.
Tuy nhiên, tôi thường làm điều này khi tôi phân tích chuỗi và chuyển đổi thành số (đặc biệt là trong các dự án ánh xạ được sử dụng một lần và loại bỏ nhiều lần).
boolean isNonZeroNumber = false;
try {
if(StringUtils.isNotBlank(s) && new BigDecimal(s).compareTo(BigDecimal.ZERO) != 0) {
b = true;
}
} catch(NumberFormatException e) {
//swallow this exception; b stays false.
}
return b;
Trong một số trường hợp, ngoại lệ hoàn toàn không phải là ngoại lệ; trong thực tế, nó được mong đợi Xem xét ví dụ này:
/* Check if the process is still alive; exitValue() throws an exception if it is */
try {
p.exitValue();
processPool.remove(p);
}
catch (IllegalThreadStateException e) { /* expected behaviour */ }
Vì không có phương thức isAlive () trong java.lang.Process (), nên cách duy nhất để kiểm tra xem nó có còn sống hay không là gọi exitValue (), ném IllegalThreadStateException nếu quá trình vẫn đang chạy.
Theo kinh nghiệm khiêm tốn của tôi, hiếm khi điều này là tốt. Bạn có thể thay đổi số dặm.
Gần như mỗi lần tôi nhìn thấy điều này trong cơ sở mã của chúng tôi, đó là vì tôi đã theo dõi một lỗi mà ngoại lệ ăn được đã ẩn. Nói cách khác, bằng cách không cung cấp bất kỳ mã nào, ứng dụng không có cách nào để chỉ ra lỗi hoặc thực hiện một hành động khác.
Đôi khi, tại các lớp API chẳng hạn, bạn có thể không muốn hoặc không thể để ngoại lệ vượt qua, vì vậy trong trường hợp đó, tôi có xu hướng thử và bắt những cái chung nhất, sau đó ghi nhật ký. Một lần nữa, ít nhất là cho một phiên gỡ lỗi / chẩn đoán một cơ hội.
Thông thường, nếu nó phải trống, ít nhất tôi làm là đưa ra một khẳng định nào đó, vì vậy ít nhất một cái gì đó xảy ra trong một phiên gỡ lỗi. Điều đó nói rằng, nếu tôi không thể xử lý nó, tôi có xu hướng bỏ qua chúng hoàn toàn.
IMO có một nơi mà các câu lệnh bắt trống là OK. Trong các trường hợp thử nghiệm mà bạn mong đợi một ngoại lệ:
try
{
DoSomething(); //This should throw exception if everything works well
Assert.Fail('Expected exception was not thrown');
}
catch(<whatever exception>)
{
//Expected to get here
}
Tôi tin rằng có một số trường hợp nhất định trong đó có một điều khoản bắt trống - đây là những trường hợp khi bạn muốn mã chỉ tiếp tục nếu một hoạt động cụ thể thất bại. Tuy nhiên, tôi nghĩ rằng mô hình này có thể dễ dàng bị lạm dụng, vì vậy mỗi lần sử dụng nên được kiểm tra chặt chẽ để đảm bảo không có cách nào tốt hơn để xử lý nó. Cụ thể, điều này không bao giờ được thực hiện nếu nó khiến chương trình ở trạng thái không nhất quán hoặc nếu nó có thể dẫn đến một số phần khác của mã bị lỗi sau này.
Tôi không tin vào việc không có một số mức độ cảnh báo khi có ngoại lệ xảy ra - không phải một trong những mục tiêu của lập trình là cải thiện mã? Nếu một ngoại lệ xảy ra 10% thời gian và bạn không bao giờ biết về nó, thì ngoại lệ đó sẽ luôn tệ đến mức đó hoặc tệ hơn.
Tuy nhiên, tôi thấy mặt khác, rằng nếu ngoại lệ không có tác hại thực sự trong việc xử lý mã, thì tại sao lại phơi bày người dùng với nó. Giải pháp tôi thường thực hiện là ghi nhật ký bởi lớp logger của tôi (đó là trong mỗi lớp tôi từng viết tại nơi làm việc).
Nếu đó là một ngoại lệ lành tính, thì tôi thực hiện cuộc gọi đến phương thức .Debug () của Logger; mặt khác, Logger.Error () (và (có thể) ném).
try
{
doWork();
}
catch(BenignException x)
{
_log.Debug("Error doing work: " + x.Message);
}
Nhân tiện, khi tôi thực hiện trình ghi nhật ký của mình, thực hiện cuộc gọi đến phương thức .Debug () sẽ chỉ ghi nhật ký nếu tệp App.Config của tôi chỉ định mức nhật ký thực thi chương trình ở chế độ Gỡ lỗi.
Kiểm tra sự tồn tại là một trường hợp sử dụng tốt:
// If an exception happens, it doesn't matter. Log the initial value or the new value
function logId(person) {
let id = 'No ID';
try {
id = person.data.id;
} catch {}
console.log(id);
}
Một trường hợp khác là khi một finally
mệnh đề được sử dụng:
function getter(obj){}
function objChecker()
{
try
{
/* Check argument length and constructor type */
if (getter.length === 1 && getter.constructor === Function)
{
console.log("Correct implementation");
return true;
}
else
{
console.log("Wrong implementation");
return false;
}
}
catch(e)
{
}
finally
{
console.log(JSON.stringify(getter))
}
}
// Test the override of the getter method
getter = getter;
objChecker();
getter = [];
objChecker();
getter = {};
objChecker();
getter = RegExp;
objChecker();
getter = Function;
objChecker();
Có một đề xuất cho phép bỏ qua ràng buộc bắt trong ECMAScript liên quan đến trường hợp sử dụng này và các trường hợp sử dụng tương tự.
Người giới thiệu
Lần duy nhất tôi thực sự cần phải làm một cái gì đó như thế này là với một lớp ghi nhật ký cho một ứng dụng giao diện điều khiển. Có một trình xử lý bắt toàn cầu cấp cao nhất đã phát ra lỗi thành STDOUT, ghi lại lỗi vào một tệp, sau đó đóng ứng dụng với mã lỗi> 0.
Vấn đề ở đây là đôi khi, việc đăng nhập vào tập tin thất bại. Quyền truy cập thư mục ngăn bạn viết tệp, tệp bị khóa riêng, bất cứ điều gì. Nếu điều đó xảy ra, tôi không thể xử lý ngoại lệ giống như cách tôi đã có ở nơi khác (bắt, ghi nhật ký các chi tiết có liên quan , bọc trong một loại ngoại lệ tốt hơn, v.v.) vì việc ghi nhật ký các chi tiết ngoại lệ khiến trình ghi chép phải trải qua các hành động tương tự ( cố gắng ghi vào một tập tin) đã thất bại. Khi họ thất bại lần nữa ... Bạn thấy tôi đang đi đâu. Nó được vào một vòng lặp vô hạn.
Nếu bạn bỏ một số khối {} thử, bạn có thể kết thúc ngoại lệ xuất hiện trong hộp thông báo (không phải những gì bạn muốn cho ứng dụng cấu hình im lặng). Vì vậy, trong phương thức ghi vào tệp nhật ký, tôi có một trình xử lý bắt trống. Điều này không chôn vùi lỗi vì bạn vẫn nhận được mã lỗi> 0, nó chỉ dừng vòng lặp vô hạn và cho phép ứng dụng thoát một cách duyên dáng.
Có một bình luận tất nhiên, giải thích tại sao nó trống rỗng.
(Tôi sẽ đăng bài này sớm hơn, tôi chỉ sợ bị vùi vào quên lãng. Mặc dù tôi không phải là người duy nhất, mặc dù ...)
Sẽ ổn trong trường hợp khi một số trình tự phải được thực hiện bất kể điều gì với phần quan trọng nhất được đặt ở cuối.
Ví dụ. Trong giao tiếp điều khiển chuyển động của máy chủ để điều khiển. Trong các tình huống khẩn cấp, có một số bước chuẩn bị để hủy bỏ chuyển động, ngừng tạo quỹ đạo, giảm tốc động cơ, cho phép ngắt, vô hiệu hóa bộ khuếch đại và sau đó, bạn phải tiêu diệt năng lượng xe buýt. Tất cả phải diễn ra tuần tự và nếu một trong các bước không thành công thì các bước còn lại phải được thực hiện ngay cả khi có nguy cơ làm hỏng phần cứng được chấp nhận. Nói ngay cả khi tất cả các bên trên không thành công, sức mạnh xe buýt giết chết dù sao cũng phải xảy ra.
Đóng tài nguyên hệ thống một cách duyên dáng để phục hồi từ một lỗi
Ví dụ. Nếu bạn đang chạy một dịch vụ trong nền mà không cung cấp thông tin phản hồi cho người dùng, bạn có thể không muốn đẩy một dấu hiệu của lỗi cho người dùng nhưng bạn làm cần phải đóng ra các nguồn lực được sử dụng một cách duyên dáng.
try
{
// execution code here
}
catch(Exception e)
{
// do nothing here
}
finally
{
// close db connection
// close file io resource
// close memory stream
// etc...
}
Lý tưởng nhất là bạn sử dụng lệnh bắt trong chế độ gỡ lỗi để bắt lỗi và in chúng ra bàn điều khiển hoặc vào tệp nhật ký để kiểm tra. Trong môi trường sản xuất, các dịch vụ nền thường được dự kiến sẽ không làm gián đoạn người dùng khi ném lỗi để đầu ra lỗi phải được loại bỏ.