Sử dụng try / catch để ngăn ứng dụng bị treo


79

Tôi đã và đang làm việc trên một ứng dụng Android try/catchthường xuyên sử dụng để ngăn nó gặp sự cố ngay cả ở những nơi không cần thiết. Ví dụ,

Một chế độ xem trong xml layoutvới id = toolbarđược tham chiếu như:

// see new example below, this one is just confusing
// it seems like I am asking about empty try/catch
try {
    View view = findViewById(R.id.toolbar);
}
catch(Exception e) {
}

Cách tiếp cận này được sử dụng trong toàn bộ ứng dụng. Dấu vết ngăn xếp không được in và thực sự khó để tìm ra điều gì đã xảy ra. Ứng dụng đóng đột ngột mà không in bất kỳ dấu vết ngăn xếp nào.

Tôi yêu cầu tiền bối giải thích cho tôi và anh ấy nói,

Điều này là để ngăn ngừa sự cố trong quá trình sản xuất.

Tôi hoàn toàn không đồng ý với nó . Đối với tôi, đây không phải là cách để ngăn các ứng dụng bị treo. Nó cho thấy rằng nhà phát triển không biết mình đang làm gì và đang nghi ngờ.

Đây có phải là cách tiếp cận đang được sử dụng trong ngành để ngăn các ứng dụng doanh nghiệp gặp sự cố không?

Nếu try/catchthực sự, thực sự nhu cầu của chúng ta thì liệu có thể đính kèm một trình xử lý ngoại lệ với chuỗi giao diện người dùng hoặc các chuỗi khác và bắt mọi thứ ở đó không? Đó sẽ là một cách tiếp cận tốt hơn nếu có thể.

Đúng, trống try/catchlà không tốt và ngay cả khi chúng tôi in dấu vết ngăn xếp hoặc ngoại lệ nhật ký cho máy chủ, việc gói các khối mã try/catchngẫu nhiên trên tất cả các ứng dụng không có ý nghĩa đối với tôi, ví dụ: khi mọi chức năng được bao bọc trong a try/catch.

CẬP NHẬT

Vì câu hỏi này đã được rất nhiều người chú ý và một số người đã hiểu sai câu hỏi (có lẽ vì tôi chưa diễn đạt rõ ràng) nên tôi sẽ diễn đạt lại nó.

Đây là những gì các nhà phát triển đang làm ở đây

  • Một chức năng được viết và thử nghiệm , nó có thể là một chức năng nhỏ chỉ khởi tạo các khung nhìn hoặc một chức năng phức tạp, sau khi thử nghiệm, nó được bao bọc xung quanh try/catchkhối. Ngay cả đối với hàm sẽ không bao giờ ném ra bất kỳ ngoại lệ nào.

  • Thực hành này được sử dụng trong toàn bộ ứng dụng. Đôi khi dấu vết ngăn xếp được in và đôi khi chỉ là một debug logthông báo lỗi ngẫu nhiên. Thông báo lỗi này khác nhau giữa các nhà phát triển.

  • Với cách tiếp cận này, ứng dụng không bị lỗi nhưng hành vi của ứng dụng trở nên không xác định. Thậm chí đôi khi thật khó để theo dõi những gì đã xảy ra.

  • Câu hỏi thực sự tôi đã hỏi là; Đó có phải là thông lệ đang được áp dụng trong ngành để ngăn chặn các ứng dụng doanh nghiệp bị treo? và tôi không hỏi về thử / bắt trống . Có phải người dùng yêu thích ứng dụng không bị treo hơn ứng dụng hoạt động bất ngờ không? Bởi vì nó thực sự dẫn đến sự cố hoặc làm cho người dùng thấy màn hình trống hoặc hành vi mà người dùng không biết.

  • Tôi đang đăng một vài đoạn mã từ mã thực ở đây

      private void makeRequestForForgetPassword() {
        try {
            HashMap<String, Object> params = new HashMap<>();
    
            String email= CurrentUserData.msisdn;
            params.put("email", "blabla");
            params.put("new_password", password);
    
            NetworkProcess networkProcessForgetStep = new NetworkProcess(
                serviceCallListenerForgotPasswordStep, ForgotPassword.this);
            networkProcessForgetStep.serviceProcessing(params, 
                Constants.API_FORGOT_PASSWORD);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
     private void languagePopUpDialog(View view) {
        try {
            PopupWindow popupwindow_obj = popupDisplay();
            popupwindow_obj.showAsDropDown(view, -50, 0);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    void reloadActivity() {
        try {
            onCreateProcess();
        } catch (Exception e) {
        }
    }
    

không trùng lặp với các phương pháp hay nhất về xử lý ngoại lệ của Android , OP đang cố gắng bắt ngoại lệ cho một mục đích khác với câu hỏi này.


11
Không trả lời câu hỏi của bạn, nhưng không bao giờ sliently nuốt ngoại lệ catch(Exception e){}- nhận xét này có ý nghĩa trước khi chỉnh sửa cho câu hỏi
Scary Wombat


29
Ah, khét tiếngON ERROR RESUME NEXT
Deduplicator

Nhận xét không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
Bhargav Rao

1
Câu hỏi này khiến tôi suy nghĩ, bởi vì tôi cũng sử dụng thử {} catch (Exception e) {} nhiều lần khi tôi sắp hết thời gian
Raut Darpan

Câu trả lời:


81

Tất nhiên, luôn có những ngoại lệ đối với các quy tắc, nhưng nếu bạn cần một quy tắc ngón tay cái - thì bạn đã đúng; các khối bắt trống là "hoàn toàn" thực hành xấu.

Hãy xem xét kỹ hơn, trước tiên hãy bắt đầu với ví dụ cụ thể của bạn:

try {
  View view = findViewById(R.id.toolbar);
}
catch(Exception e) { }

Vì vậy, một tham chiếu đến một cái gì đó được tạo ra; và khi điều đó không thành công ... nó không quan trọng; bởi vì tham chiếu đó không được sử dụng ngay từ đầu! Đoạn mã trên hoàn toàn vô ích . Hay người viết mã đó ban đầu cho rằng một cuộc gọi thứ hai, tương tự sẽ không còn ngoại lệ nữa?!

Có thể điều này có nghĩa là:

try {
  View view = findViewById(R.id.toolbar);
  ... and now do something with that view variable ...
}
catch(Exception e) { }

Nhưng một lần nữa, điều này giúp ích gì ?! Trường hợp ngoại lệ tồn tại để giao tiếp tương ứng Tuyên truyền các tình huống lỗi trong mã của bạn. Bỏ qua lỗi hiếm khi là một ý kiến ​​hay. Trên thực tế, một ngoại lệ có thể được xử lý theo những cách như:

  • Bạn đưa ra phản hồi cho người dùng; (như: "giá trị bạn đã nhập không phải là một chuỗi, hãy thử lại"); hoặc tham gia vào việc xử lý lỗi phức tạp hơn
  • Có thể bằng cách nào đó vấn đề được mong đợi và có thể được giảm nhẹ (ví dụ: bằng cách đưa ra câu trả lời "mặc định" khi một số "tìm kiếm từ xa" không thành công)
  • ...

Câu chuyện ngắn: điều tối thiểu bạn làm với một ngoại lệ là ghi lại / theo dõi nó; để sau này khi bạn gỡ lỗi một số vấn đề, bạn hiểu "OK, tại thời điểm này ngoại lệ đã xảy ra".

Và như những người khác đã chỉ ra: bạn cũng tránh bắt lỗi Ngoại lệ nói chung (tốt, tùy thuộc vào lớp: có thể có lý do chính đáng để có một số lỗi đối với Ngoại lệ và thậm chí một số loại Lỗi ở cấp cao nhất, để đảm bảo rằng không có gì bị mất; không bao giờ ).

Cuối cùng, hãy trích dẫn Ward Cunningham:

Bạn biết rằng bạn đang làm việc với mã sạch khi mỗi quy trình bạn đọc hóa ra lại giống như những gì bạn mong đợi. Bạn có thể gọi nó là mã đẹp khi mã cũng làm cho nó giống như ngôn ngữ được tạo ra cho vấn đề.

Hãy để điều đó chìm vào và suy ngẫm về nó. Mã sạch không làm bạn ngạc nhiên. Ví dụ bạn đang hiển thị cho chúng tôi ngạc nhiên mọi người nhìn vào.

Cập nhật , liên quan đến bản cập nhật mà OP hỏi về

try {
  do something
}
catch(Exception e) { 
  print stacktrace
}

Câu trả lời tương tự: làm điều đó "khắp nơi" cũng là thực hành xấu . Vì đoạn mã này cũng gây ngạc nhiên cho người đọc.

Ở trên:

  • In thông tin lỗi ở đâu đó. Hoàn toàn không đảm bảo rằng "một nơi nào đó" giống một điểm đến hợp lý . Ngược lại. Ví dụ: trong ứng dụng mà tôi đang làm việc, các lệnh gọi như vậy sẽ xuất hiện một cách kỳ diệu trong bộ đệm theo dõi của chúng tôi. Tùy thuộc vào ngữ cảnh, ứng dụng của chúng tôi đôi khi có thể bơm hàng tấn dữ liệu vào các bộ đệm đó; làm cho những vùng đệm đó bị cắt bớt sau mỗi vài giây. Vì vậy, "just print error" thường được dịch là: "đơn giản là mất tất cả thông tin lỗi như vậy".
  • Sau đó: bạn không thử / bắt vì bạn có thể . Bạn làm điều đó bởi vì bạn hiểu mã của bạn đang làm gì; và bạn biết đấy: Tốt hơn là tôi nên thử / nắm bắt ở đây để làm đúng (xem lại phần đầu tiên của câu trả lời của tôi).

Vì vậy, sử dụng try / catch làm "mẫu" như bạn đang hiển thị; như đã nói: vẫn không phải là một ý kiến ​​hay. Và có, nó ngăn chặn sự cố; nhưng dẫn đến tất cả các loại hành vi "không xác định". Bạn biết đấy, khi bạn chỉ bắt gặp một ngoại lệ thay vì xử lý nó đúng cách ; bạn mở một lon giun; vì bạn có thể gặp phải vô số lỗi tiếp theo mà sau này bạn không hiểu. Bởi vì bạn đã sử dụng sự kiện "nguyên nhân gốc rễ" trước đó; in nó ở đâu đó; và một nơi nào đó giờ đã biến mất.


1
Nếu tôi in dấu vết ngăn xếp thì sao? Tôi vẫn không nghĩ rằng tôi cần thử / nắm bắt ở đây.
mallaudin

3
Tôi phải thừa nhận rằng tôi không nhận được chỉnh sửa của bạn. Không phải là một ý tưởng thực sự bạn đang làm gì ở đó; hoặc nơi bạn đang nhận được với điều này.
GhostCat

@mallaudin trong trường hợp chung, bất kỳ thứ gì sau dòng bị lỗi chương trình sẽ không được thực thi (obvs), vì vậy việc in ấn chỉ là vô nghĩa. Trong trường hợp cụ thể này, tức là hãy thử + ngoại trừ, ít nhất một cái gì đó sẽ hiển thị và ngoại lệ sẽ không bị tắt tiếng.
Peter Badida

2
@GhostCat OP cho biết trong một nhận xét trong một câu trả lời khác rằng các khối ngoại lệ đã chứa các lệnh gọi ghi nhật ký. Câu hỏi trình bày sai những gì đang thực sự xảy ra, vì vậy tôi không nghĩ rằng việc buộc tội nhà phát triển cấp cao là không đủ năng lực là hữu ích ở đây. Tôi nghĩ rằng còn nhiều điều đang diễn ra ngoài những gì OP đang mang lại cho chúng ta.
jpmc 26

1
@GhostCat nó không phải về repo, tôi chỉ nhận ra ví dụ của tôi là xấu. Ai cũng nghĩ tôi đang hỏi về sản phẩm nào try / catch
mallaudin

15

Từ tài liệu Android :

Hãy cho phép nó là -

Không nắm bắt ngoại lệ chung

Nó cũng có thể bị cám dỗ để trở nên lười biếng khi bắt các ngoại lệ và làm những việc như sau:

try {
    someComplicatedIOFunction();        // may throw IOException
    someComplicatedParsingFunction();   // may throw ParsingException
    someComplicatedSecurityFunction();  // may throw SecurityException
    // phew, made it all the way
} catch (Exception e) {                 // I'll just catch all exceptions
    handleError();                      // with one generic handler!
}

Trong hầu hết các trường hợp, bắt chung chung Exceptionhoặc Có thể ném là không phù hợp (tốt nhất là không Thể ném vì nó bao gồm các ngoại lệ Lỗi). Điều đó rất nguy hiểm vì nó có nghĩa là các Ngoại lệ mà bạn không bao giờ mong đợi (bao gồm cả lượt RuntimeExceptionsthích ClassCastException) bị bắt trong việc xử lý lỗi cấp ứng dụng.

Nó che khuất các thuộc tính xử lý lỗi trong mã của bạn, có nghĩa là nếu ai đó thêm một loại Exceptionmã mới vào mã bạn đang gọi, trình biên dịch sẽ không giúp bạn nhận ra rằng bạn cần phải xử lý lỗi theo cách khác .

Các giải pháp thay thế để bắt Ngoại lệ chung:

  • Bắt từng ngoại lệ riêng biệt dưới dạng các khối bắt riêng biệt sau một lần thử. Điều này có thể khó xử nhưng vẫn tốt hơn nếu bắt tất cả các Ngoại lệ.
    Chỉnh sửa của tác giả: Cái này do tôi lựa chọn. Hãy cẩn thận lặp lại quá nhiều mã trong các khối bắt. Nếu bạn đang sử dụng Java 7 trở lên, hãy sử dụng multi-catch để tránh lặp lại cùng một khối catch.
  • Cấu trúc lại mã của bạn để xử lý lỗi chi tiết hơn , với nhiều khối thử. Tách IO khỏi phân tích cú pháp, xử lý lỗi riêng trong từng trường hợp.
  • Ném lại ngoại lệ . Nhiều khi bạn không cần phải bắt ngoại lệ ở cấp độ này, chỉ cần để phương pháp ném nó.

Trong hầu hết các trường hợp, bạn không nên xử lý các loại ngoại lệ khác nhau theo cùng một cách.

Định dạng / paragraphing được sửa đổi một chút từ nguồn cho câu trả lời này.

PS Đừng sợ ngoại lệ !! Họ là bạn bè!!!


1
nếu bạn nắm bắt từng ngoại lệ riêng, hãy chắc chắn để tránh tiếp tục thực hiện trong tình trạng không chắc chắn (tránh những thứ như Object a; try { a = thing(); } catch (Exception e) {...} try { a.action(); } catch (Exception e) {...}))
njzk2

Công bằng mà nói, bắt chung chung Exceptioncó thể hữu ích như là một phần của hệ thống "ghi nhật ký trước khi gặp sự cố", mặc dù nó sẽ phát triển lại trong trường hợp đó.
Justin Time - Phục hồi Monica

9

Tôi sẽ đặt điều này như một bình luận cho một số câu trả lời khác, nhưng tôi chưa có danh tiếng cho điều đó.

Bạn đúng khi nói rằng đó là hành vi xấu, trên thực tế, những gì bạn đã đăng cho thấy các kiểu thực hành xấu khác nhau liên quan đến các trường hợp ngoại lệ.

  1. Thiếu xử lý lỗi
  2. Bắt chung
  3. Không có ngoại lệ cố ý
  4. Chăn Thử / bắt

Tôi sẽ cố gắng giải thích tất cả những điều đó thông qua ví dụ này.

try {
   User user = loadUserFromWeb();     
   if(user.getCountry().equals("us")) {  
       enableExtraFields();
   }
   fillFields(user);   
} catch (Exception e) { 
}

Điều này có thể không thành công theo một số cách nên được xử lý khác nhau.

  1. Các trường sẽ không được điền, vì vậy người dùng được hiển thị với một màn hình trống và sau đó ... làm gì? Không có gì - thiếu xử lý lỗi.
  2. Không có sự phân biệt giữa các loại lỗi khác nhau, ví dụ như sự cố Internet hoặc sự cố với chính máy chủ (ngừng hoạt động, yêu cầu bị hỏng, đường truyền bị hỏng, ...) - Bắt chung.
  3. Bạn không thể sử dụng ngoại lệ cho mục đích của riêng mình vì hệ thống hiện tại can thiệp vào điều đó. - Không có ngoại lệ cố ý
  4. Các lỗi không mong muốn và không mong muốn (ví dụ: null.equals (...)) có thể khiến mã thiết yếu không thực thi. - Thử / bắt chăn

Các giải pháp

(1) Trước hết, thất bại âm thầm không phải là điều tốt. Nếu có lỗi, ứng dụng sẽ không hoạt động. Thay vào đó, nên có một nỗ lực để giải quyết sự cố hoặc hiển thị một cảnh báo, ví dụ: "Không thể tải dữ liệu người dùng, có thể bạn chưa kết nối với Internet?". Nếu ứng dụng không làm những gì nó phải làm, đó là cách khiến người dùng khó chịu hơn là nếu nó chỉ tự đóng.

(4) Nếu Người dùng không đầy đủ, ví dụ: quốc gia không được biết và trả về giá trị rỗng. Phương thức bằng sẽ tạo ra một NullPointerException. Nếu NPE đó được ném và bắt như trên, phương thức fillFields (người dùng) sẽ không được gọi, mặc dù nó vẫn có thể được thực thi mà không gặp sự cố. Bạn có thể ngăn chặn điều này bằng cách bao gồm kiểm tra rỗng, thay đổi thứ tự thực thi hoặc điều chỉnh phạm vi thử / bắt. (Hoặc bạn có thể lưu mã hóa như sau: "us" .equals (user.getCountry ()), nhưng tôi phải cung cấp một ví dụ). Tất nhiên, bất kỳ ngoại lệ nào khác cũng sẽ ngăn fillFields () được thực thi, nhưng nếu không có người dùng, bạn có thể không muốn nó được thực thi.

(1, 2, 3) Tải từ web thường ném ra nhiều loại ngoại lệ, từ ngoại lệ IOException đến HttpMessageNotReadable thậm chí chỉ trả về. Có thể là người dùng không kết nối với internet, có thể đã có sự thay đổi đối với máy chủ phụ trợ hoặc máy chủ bị lỗi, nhưng bạn không biết vì bạn bắt được (Ngoại lệ) - thay vào đó, bạn nên bắt các ngoại lệ cụ thể. Bạn thậm chí có thể bắt gặp một vài trong số chúng như thế này

try{
   User user = loadUserFromWeb(); //throws NoInternetException, ServerNotAvailableException or returns null if user does not exist
   if(user == null) { 
       throw new UserDoesNotExistException(); //there might be better options to solve this, but it highlights how exceptions can be used.
   }
   fillFields(user);
   if("us".equals(user.getCountry()) {
       enableExtraFields();
   }
} catch(NoInternetException e){
    displayWarning("Your internet conneciton is down :(");
} catch(ServerNotAvailableException e){
    displayWarning("Seems like our server is having trouble, try again later.");
} catch(UserDoesNotExistException e){
    startCreateUserActivity();
}

Tôi hy vọng điều đó giải thích nó.

Ít nhất là một cách khắc phục nhanh chóng, những gì bạn có thể làm là gửi một sự kiện đến chương trình phụ trợ của bạn với ngoại lệ. Ví dụ: thông qua firebase hoặc crashlytics. Bằng cách đó, ít nhất bạn có thể thấy những thứ như (này, hoạt động chính không tải đối với 80% người dùng của chúng tôi do sự cố như (4).


8

Đó chắc chắn là một thực hành lập trình tồi.

Theo kịch bản hiện tại, nếu có hàng trăm trường hợp try catchnhư thế này, thì bạn thậm chí sẽ không biết ngoại lệ xảy ra ở đâu nếu không gỡ lỗi ứng dụng, đó là một cơn ác mộng nếu ứng dụng của bạn ở trong môi trường sản xuất.

Nhưng bạn có thể bao gồm một trình ghi nhật ký để bạn biết khi nào một ngoại lệ được đưa ra (và tại sao). Nó sẽ không thay đổi quy trình làm việc bình thường của bạn.

...
try {
    View view = findViewById(R.id.toolbar);
}catch(Exception e){
    logger.log(Level.SEVERE, "an exception was thrown", e);
}
...

7

Đây là một thực hành xấu. Các câu trả lời khác đã nói điều đó nhưng tôi nghĩ điều quan trọng là phải lùi lại và hiểu lý do tại sao chúng ta có những ngoại lệ ngay từ đầu.

Mọi hàm đều có hậu điều kiện - một tập hợp tất cả những thứ phải đúng sau khi hàm đó thực thi. Ví dụ, một hàm đọc từ tệp có điều kiện đăng là dữ liệu trong tệp sẽ được đọc từ đĩa và trả về. Do đó, một ngoại lệ được đưa ra khi một hàm không thể thỏa mãn một trong các điều kiện sau của nó.

Bằng cách bỏ qua một ngoại lệ từ một chức năng (hoặc thậm chí bỏ qua nó một cách hiệu quả bằng cách ghi lại ngoại lệ), bạn đang nói rằng bạn ổn với chức năng đó nhưng không thực sự thực hiện tất cả công việc mà nó đã đồng ý. Điều này có vẻ khó xảy ra - nếu một chức năng không chạy chính xác, không có gì đảm bảo rằng những gì tiếp theo sẽ chạy. Và nếu phần còn lại của mã của bạn chạy tốt cho dù một chức năng cụ thể có chạy đến khi hoàn thành hay không, thì người ta sẽ tự hỏi tại sao bạn lại có chức năng đó ngay từ đầu.

[Bây giờ có một số trường hợp mà các catches trống là ok. Ví dụ, ghi nhật ký là một cái gì đó mà bạn có thể biện minh cho việc gói gọn trong một khoảng trống. Ứng dụng của bạn có thể sẽ chạy tốt ngay cả khi không thể viết được một số nhật ký. Nhưng đó là những trường hợp đặc biệt mà bạn phải rất vất vả mới tìm được trong một ứng dụng bình thường.]

Vì vậy, vấn đề ở đây là, đây là một phương pháp không tốt vì nó không thực sự giữ cho ứng dụng của bạn chạy (lý do được cho là lý do cho phong cách này). Có thể về mặt kỹ thuật, hệ điều hành đã không giết nó. Nhưng không chắc rằng ứng dụng vẫn chạy bình thường sau khi bỏ qua một ngoại lệ. Và trong trường hợp xấu nhất, nó thực sự có thể gây hại (ví dụ: làm hỏng tệp người dùng, v.v.).


3

Điều này không tốt vì nhiều lý do:

  1. Bạn đang làm gì mà findViewByIdném ra một Ngoại lệ? Hãy sửa điều đó (và cho tôi biết, vì tôi chưa bao giờ thấy điều này) thay vì bắt.
  2. Đừng nắm bắt Exceptionkhi nào bạn có thể bắt gặp một loại ngoại lệ cụ thể.
  3. Có niềm tin rằng các ứng dụng tốt sẽ không bị lỗi. Đo không phải sự thật. Một ứng dụng tốt sẽ bị treo nếu nó phải.

Nếu một ứng dụng rơi vào trạng thái tồi tệ, tốt hơn là để nó bị sập còn hơn là để nó hoạt động ở trạng thái không sử dụng được. Khi một người nhìn thấy một NPE, người ta không nên chỉ cần kiểm tra rỗng và bỏ đi. Cách tốt hơn là tìm hiểu lý do tại sao một cái gì đó là null và ngăn nó không bị null hoặc (nếu null kết thúc là trạng thái hợp lệ và được mong đợi) kiểm tra null. Nhưng bạn phải hiểu tại sao vấn đề xảy ra ngay từ đầu.


2

Tôi đã phát triển các ứng dụng Android trong 4-5 năm qua và chưa bao giờ sử dụng thử bắt để khởi tạo chế độ xem.

Nếu thanh công cụ của nó như thế này

Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);

ví dụ: - Để lấy TextView từ một dạng xem (phân đoạn / hộp thoại / bất kỳ dạng xem tùy chỉnh nào)

TextView textview = (TextView) view.findViewById(R.id.viewId);

TextView textview = (TextView) view.findViewById (R.id.viewId);

thay vì cái này

View view = findViewById(R.id.toolbar);

Đối tượng xem có phạm vi tiếp cận tối thiểu so với loại chế độ xem thực của nó.

Lưu ý: - Có thể nó bị treo do chế độ xem đã được tải. Nhưng thêm thử bắt là một thực hành không tốt.


Trong nhiều trường hợp, việc truyền chế độ xem là không cần thiết. Có một số phương thức mà bạn có trên Viewđó có thể hữu ích (như setVisibility()), mà bạn không cần chỉ định chính xác lớp nào được sử dụng. (ví dụ: trong trường hợp bố cục, có thể dễ bị thay đổi theo thời gian)
njzk2

1

Có, try / catch được sử dụng để ngăn ứng dụng bị treo nhưng Bạn chắc chắn không cần try / catch để tìm nạp chế độ xem từ XML như được mô tả trong câu hỏi của bạn.

try / catch thường được sử dụng trong khi thực hiện bất kỳ yêu cầu http nào, trong khi phân tích cú pháp bất kỳ Chuỗi thành URL nào, tạo kết nối URL, v.v. và cũng đảm bảo in dấu vết ngăn xếp. Không in nó không có ý nghĩa nhiều trong việc bao quanh nó bằng try / catch.


1

Như đã nói trước đây, các ngoại lệ chung không nên được vá hoặc ít nhất là chỉ ở một số vị trí trung tâm (thường nằm trong mã khung / cơ sở hạ tầng, không phải mã ứng dụng). Nếu bắt được các ngoại lệ chung và ghi nhật ký nó, ứng dụng phải được tắt sau đó hoặc ít nhất người dùng phải được thông báo rằng ứng dụng có khả năng ở trạng thái không ổn định và có thể xảy ra hỏng dữ liệu (nếu người dùng chọn tiếp tục thực thi). Bởi vì đây là điều có thể xảy ra nếu bạn bắt gặp tất cả các loại ngoại lệ (hết bộ nhớ để đặt tên) và để ứng dụng ở trạng thái không xác định.

IMHO, việc nuốt các ngoại lệ và nguy cơ toàn vẹn dữ liệu, mất dữ liệu hoặc đơn giản là để ứng dụng ở trạng thái không xác định còn tệ hơn là để ứng dụng gặp sự cố và người dùng biết rằng đã xảy ra lỗi và có thể thử lại. Điều này cũng sẽ dẫn đến các vấn đề được báo cáo tốt hơn (nhiều hơn ở gốc rễ của vấn đề), có thể ít các triệu chứng khác nhau hơn nếu người dùng của bạn bắt đầu báo cáo tất cả các loại sự cố bắt nguồn từ trạng thái ứng dụng không xác định.

Sau khi xử lý ngoại lệ trung tâm / ghi nhật ký / báo cáo và tắt máy có kiểm soát, hãy bắt đầu viết lại xử lý ngoại lệ để nắm bắt các ngoại lệ cục bộ càng cụ thể càng tốt. Cố gắng làm cho khối try {} càng ngắn càng tốt.


1

Hãy để tôi nói thêm quan điểm của mình, với tư cách là một chàng trai làm việc trong ngành phát triển thiết bị di động của công ty trong hơn một thập kỷ. Đầu tiên, một số mẹo chung về các trường hợp ngoại lệ, hầu hết đều có trong các câu trả lời ở trên:

  • Các trường hợp ngoại lệ nên được sử dụng cho các tình huống ngoại lệ, bất ngờ hoặc không kiểm soát được, không phải thường xuyên trong toàn bộ mã.
  • Một lập trình viên phải biết các phần mã dễ bị ném ngoại lệ và cố gắng bắt chúng, để phần còn lại của mã sạch nhất có thể.
  • Các trường hợp ngoại lệ không nên để im lặng, như một quy tắc chung.

Bây giờ, khi bạn không phát triển ứng dụng cho chính mình mà cho một công ty hoặc tập đoàn, bạn thường phải đối mặt với các yêu cầu bổ sung về chủ đề này:

  • "Sự cố ứng dụng cho thấy một hình ảnh xấu của công ty, vì vậy họ không thể chấp nhận được". Sau đó, phát triển cẩn thận nên được thực hiện và bắt ngay cả những trường hợp ngoại lệ không thể xảy ra có thể là một lựa chọn. Nếu vậy, điều này phải được thực hiện một cách có chọn lọc và giữ trong giới hạn hợp lý. Và lưu ý rằng sự phát triển không phải là tất cả về các dòng mã, ví dụ, một quá trình kiểm tra chuyên sâu là rất quan trọng trong những trường hợp này. Tuy nhiên, hành vi không mong muốn trong một ứng dụng công ty còn tệ hơn sự cố. Vì vậy, bất cứ khi nào bạn bắt gặp một ngoại lệ trong ứng dụng của mình, bạn phải biết phải làm gì, hiển thị những gì và ứng dụng sẽ hoạt động như thế nào tiếp theo. Nếu bạn không thể kiểm soát điều đó, tốt hơn hết hãy để ứng dụng sập.
  • "Nhật ký và dấu vết ngăn xếp có thể đổ thông tin nhạy cảm vào bảng điều khiển. Thông tin đó có thể được sử dụng cho kẻ tấn công, vì vậy vì lý do bảo mật, chúng không thể được sử dụng trong môi trường sản xuất". Yêu cầu này mâu thuẫn với quy tắc chung cho nhà phát triển là không viết các ngoại lệ im lặng, vì vậy bạn phải tìm cách cho nó. Ví dụ: ứng dụng của bạn có thể kiểm soát môi trường, vì vậy ứng dụng sử dụng nhật ký và ngăn xếp dấu vết trong môi trường phi sản xuất, trong khi sử dụng các công cụ dựa trên đám mây như bugsense, crashlitics hoặc tương tự cho môi trường sản xuất.

Vì vậy, câu trả lời ngắn gọn là mã bạn tìm thấy nó không phải là một ví dụ thực tiễn tốt, vì nó rất khó và tốn kém để duy trì mà không cải thiện chất lượng của ứng dụng.


1

Một góc nhìn khác, là một người viết phần mềm doanh nghiệp hàng ngày, nếu một ứng dụng có lỗi không thể khắc phục được, tôi muốn nó bị sập. Đâm ra là mong muốn. Nếu nó bị treo, nó sẽ được ghi lại. Nếu nó bị lỗi nhiều lần trong một khoảng thời gian ngắn, tôi sẽ nhận được e-mail thông báo rằng ứng dụng đang gặp sự cố và tôi có thể xác minh rằng ứng dụng của chúng tôi và tất cả các dịch vụ web mà chúng tôi sử dụng vẫn đang hoạt động.

Vì vậy, câu hỏi:

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

thực hành tốt? Không! Dưới đây là một số điểm:

  1. Điều quan trọng nhất: Đây là một trải nghiệm khách hàng tồi tệ. Làm sao tôi biết khi nào có chuyện xấu đang xảy ra? Khách hàng của tôi đang cố gắng sử dụng ứng dụng của tôi và không có gì hoạt động. Họ không thể kiểm tra tài khoản ngân hàng, thanh toán hóa đơn, bất cứ điều gì ứng dụng của tôi làm. Ứng dụng của tôi hoàn toàn vô dụng, nhưng này, ít nhất nó đã không bị lỗi! (Một phần trong số tôi tin rằng nhà phát triển "Cấp cao" này nhận được điểm hạnh phúc cho số lượng sự cố thấp, vì vậy họ đang chơi trò chơi hệ thống.)

  2. Khi tôi đang phát triển và tôi viết mã xấu, nếu tôi chỉ bắt và nuốt tất cả các ngoại lệ ở lớp trên cùng thì tôi không có ghi nhật ký. Tôi không có gì trong bảng điều khiển của mình và ứng dụng của tôi bị lỗi một cách âm thầm. Từ những gì tôi có thể nói, mọi thứ dường như hoạt động ổn. Vì vậy, tôi cam kết mã ... Hóa ra đối tượng DAO của tôi đã bị vô hiệu hóa toàn bộ thời gian và các khoản thanh toán của khách hàng thực sự không bao giờ được cập nhật trong DB. Rất tiếc! Nhưng ứng dụng của tôi không bị lỗi, vì vậy đó là một điểm cộng.

  3. Đóng vai người biện hộ cho ma quỷ, giả sử tôi ổn khi bắt và nuốt mọi ngoại lệ. Rất dễ dàng để viết một trình xử lý ngoại lệ tùy chỉnh trong Android. Nếu bạn thực sự phải bắt mọi ngoại lệ, bạn có thể làm điều đó ở một nơi và không tiêu try/catchtrên toàn bộ codebase của bạn.

Một số nhà phát triển mà tôi đã từng làm việc trước đây nghĩ rằng việc bị rơi là điều tồi tệ.

Tôi phải đảm bảo với họ rằng chúng tôi muốn ứng dụng của mình gặp sự cố. Không, một ứng dụng không ổn định thì không ổn, nhưng sự cố xảy ra có nghĩa là chúng tôi đã làm sai điều gì đó và chúng tôi cần sửa nó. Nó bị hỏng càng nhanh, chúng tôi càng phát hiện ra nó sớm, thì càng dễ sửa chữa. Tùy chọn khác duy nhất mà tôi có thể nghĩ đến là cho phép người dùng tiếp tục trong một phiên bị gián đoạn, điều mà tôi cho là khiến cơ sở người dùng của tôi bực mình.


0

Đó là cách sử dụng không hợp catch(Exception e){}lý vì về cơ bản bạn đang bỏ qua lỗi. Những gì bạn có thể muốn làm là một cái gì đó giống như:

try {
    //run code that could crash here
} catch (Exception e) {
    System.out.println(e.getMessage());
}

0

Chúng tôi sử dụng khá nhiều logic tương tự của bạn. Sử dụng try-catchđể ngăn các ứng dụng sản xuất gặp sự cố.

Các trường hợp ngoại lệ KHÔNG BAO GIỜ được bỏ qua. Đó là một thực hành mã hóa tồi. Những người duy trì mã sẽ gặp khó khăn thực sự trong việc bản địa hóa phần mã đã tạo ra ngoại lệ nếu họ không được ghi lại.

Chúng tôi sử dụng Crashlyticsđể ghi lại các ngoại lệ. Mã sẽ không bị lỗi (nhưng một số chức năng sẽ bị gián đoạn). Nhưng bạn nhận được nhật ký ngoại lệ trong bảng điều khiển của Fabric/Crashlytics. Bạn có thể xem các nhật ký này và sửa các ngoại lệ.

try {
    codeThatCouldRaiseError();
} catch (Exception e) {
    e.printStackTrace();
    Crashlytics.logException(e);
}

Đúng. Đó là những gì mọi người đang làm ở đây nhưng tôi không đồng ý với nó. Đó là lý do tại sao tôi đăng câu hỏi. Bạn có thể nghĩ ra một cái gì đó hợp lý hơn không?
mallaudin

4
@mallaudin Không đăng mã mẫu trình bày sai mã bạn đang hỏi. Nó có thể thay đổi đáng kể câu trả lời mà bạn nhận được.
jpmc26

@ jpmc26 vâng. Tôi đã thấy điều đó trong các câu trả lời.
mallaudin

0

Trong khi tôi đồng ý với các phản hồi khác, có một tình huống mà tôi đã nhiều lần gặp phải mà mô típ này có thể chấp nhận được. Giả sử ai đó đã viết một đoạn mã cho một lớp như sau:

private int foo=0;

    . . .

public int getFoo() throws SomeException { return foo; }

Trong trường hợp này, phương thức 'getFoo ()' không thể bị lỗi - sẽ luôn có giá trị hợp pháp của trường riêng tư 'foo' được trả về. Tuy nhiên, một người nào đó - có lẽ vì những lý do phức tạp - đã quyết định rằng phương pháp này nên được khai báo là có khả năng tạo ra một Ngoại lệ. Nếu sau đó bạn cố gắng gọi phương thức này trong một ngữ cảnh - ví dụ như một trình xử lý sự kiện - không cho phép một ngoại lệ được đưa ra, thì về cơ bản bạn buộc phải sử dụng cấu trúc này (ngay cả khi đó, tôi đồng ý rằng ít nhất người ta nên ghi lại ngoại lệ trong trường hợp) . Bất cứ khi nào tôi phải làm điều này, tôi luôn ít nhất thêm một bình luận to béo 'ĐIỀU NÀY KHÔNG THỂ CỦA CHÚNG TÔI' bên cạnh mệnh đề 'bắt'.

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.