[java] 앱 충돌 방지를 위해 try / catch 사용

필자는 try/catch필요가없는 곳에서도 충돌을 방지하기 위해 자주 사용하는 Android 앱을 개발 하고 있습니다. 예를 들면

의보기는 다음 xml layoutid = toolbar같이 참조됩니다.

// 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) {
}

이 접근 방식은 앱 전체에서 사용됩니다. 스택 추적은 인쇄되지 않으며 무엇이 잘못되었는지 찾기가 정말 어렵습니다. 스택 추적을 인쇄하지 않고 앱이 갑자기 종료됩니다.

나는 선배에게 설명 해달라고했고 그는 말했다.

이는 프로덕션에서 충돌을 방지하기위한 것입니다.

나는 그것에 완전히 동의하지 않는다 . 나에게 이것은 앱이 충돌하는 것을 방지하는 방법이 아닙니다. 개발자 자신이 무엇을하는지 모르고 의심 스러움을 보여줍니다 .

이것이 엔터프라이즈 앱이 충돌하는 것을 방지하기 위해 업계에서 사용되는 접근 방식입니까?

경우는 try/catch정말 우리의 필요 다음, 정말이 UI 스레드 또는 다른 스레드 거기 캐치 모든 것에 예외 핸들러를 첨부 할 수 있습니까? 가능하다면 더 나은 접근 방식이 될 것입니다.

예, 비어있는 try/catch것은 좋지 않으며 서버에 스택 추적 또는 로그 예외를 인쇄하더라도 try/catch모든 앱 에서 코드 블록을 무작위로 래핑 하는 것은 나에게 의미가 없습니다 (예 : 모든 함수가 try/catch.

최신 정보

이 질문은 많은 관심을 받고 일부 사람들은 질문을 잘못 해석했기 때문에 (아마도 명확하게 표현하지 않았기 때문에) 나는 그것을 다시 표현할 것입니다.

개발자들이 여기서하는 일입니다.

  • 함수가 작성되고 테스트 되며, 테스트 후 try/catch블록을 감싸는 뷰를 초기화하는 작은 함수이거나 복잡한 함수일 수 있습니다 . 예외를 던지지 않는 함수도 마찬가지입니다.

  • 이 방법은 응용 프로그램 전체에서 사용됩니다. 때로는 스택 추적이 인쇄되고 때로는 debug log임의의 오류 메시지가 표시됩니다. 이 오류 메시지는 개발자마다 다릅니다.

  • 이 접근 방식을 사용하면 앱이 충돌하지 않지만 앱의 동작이 결정되지 않습니다. 가끔은 무엇이 잘못되었는지 따라 가기가 어렵습니다.

  • 내가 물어 본 진짜 질문은 다음과 같습니다. 엔터프라이즈 애플리케이션이 충돌하는 것을 방지하기 위해 업계에서 따르는 관행입니까? 빈 try / catch 에 대해 묻지 않습니다 . 사용자는 예기치 않게 작동하는 응용 프로그램보다 충돌하지 않는 응용 프로그램을 좋아합니까? 그것은 실제로 충돌하거나 사용자에게 빈 화면을 표시하거나 사용자가 인식하지 못하는 동작을 표시하는 것으로 귀결되기 때문입니다.

  • 여기에 실제 코드에서 몇 가지 스 니펫을 게시하고 있습니다.

      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) {
        }
    }
    

Android 예외 처리 모범 사례의 중복 이 아니며 OP
가이 질문 과 다른 목적으로 예외를 포착하려고합니다 .



답변

물론 규칙에는 항상 예외가 있지만 경험 규칙이 필요하면 맞습니다. 빈 캐치 블록은 “절대적으로”나쁜 습관입니다.

먼저 구체적인 예부터 자세히 살펴 보겠습니다.

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

그래서 무언가에 대한 참조가 생성됩니다. 그리고 그것이 실패 할 때 … 그것은 중요하지 않습니다; 그 참조는 애초에 사용되지 않기 때문입니다! 위의 코드는 전혀 쓸모없는 라인 노이즈 입니다. 아니면 그 코드를 작성한 사람이 처음에 비슷한 두 번째 호출이 더 이상 예외를 던지지 않을 것이라고 가정합니까?!

아마도 이것은 다음과 같이 보일 것입니다.

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

그러나 이것은 무엇을 도와 주는가?! 코드 내에서 각각 오류 상황을 전파 하기 위한 예외가 존재합니다 . 오류를 무시하는 것은 좋은 생각이 아닙니다. 실제로 예외는 다음과 같은 방식으로 처리 될 수 있습니다.

  • 사용자에게 피드백을 제공합니다. (예 : “입력 한 값이 문자열이 아닙니다. 다시 시도하십시오.”); 또는 더 복잡한 오류 처리에 참여
  • 아마도 문제가 예상되는 것이며 완화 될 수 있습니다 (예 : 일부 “원격 검색”이 실패 할 때 “기본”응답을 제공함).

간단히 말해서 , 예외로 할 수 있는 최소한의 일은 로그 / 추적입니다. 나중에 일부 문제를 디버깅 할 때 “OK,이 시점에서 예외가 발생했습니다”를 이해할 수 있습니다.

그리고 다른 사람과 같이 뾰족한 밖으로있다 : 당신은 또한에 대한 끼지 않도록 예외 계층에 따라 잘 (일반적으로 : 좋은 몇 가지 캐치해야하는 이유가있을 수 있습니다 예외가 있는지 확인하고, 가장 높은 수준의 오류 심지어 어떤 종류의, 아무것도 분실하지, 지금까지 ).

마지막으로 Ward Cunningham을 인용 해 보겠습니다 .

당신이 읽는 각 루틴이 당신이 기대했던 것과 거의 같을 때 당신은 깨끗한 코드로 작업하고 있다는 것을 알고 있습니다. 코드가 문제의 언어로 만들어진 것처럼 보이게 만들 때 아름다운 코드라고 부를 수 있습니다.

그것에 대해 묵상 해보세요. 깨끗한 코드는 당신을 놀라게 하지 않습니다 . 당신이 우리에게 보여주고있는 예는 보고있는 모든 사람들을 놀라게 합니다.

Update , OP에서 요청하는 업데이트 관련

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

같은 대답 : “모든 곳에서”그렇게하는 것도 나쁜 습관입니다. 이 코드이기 때문에 또한 독자를 놀라게.

위 :

  • 어딘가에 오류 정보를 인쇄합니다. 그것은이다 전혀없는 이 “어딘가”는 유사 보장 적절한 대상을. 반대로. 예 : 내가 작업중인 애플리케이션 내에서 이러한 호출은 추적 버퍼에 마술처럼 나타납니다. 상황에 따라 애플리케이션은 때때로 이러한 버퍼로 수많은 데이터를 펌핑 할 수 있습니다. 버퍼를 몇 초마다 정리합니다. 따라서 “단순한 인쇄 오류”는 종종 “단순히 모든 오류 정보를 잃어버린 것”으로 해석됩니다.
  • 그런 다음 : 당신이 때문에 당신은 시도 / 캐치하지 않을 수 있습니다 . 코드가 무엇을하는지 이해하기 때문에 그렇게합니다. 그리고 알다시피 : 나는 올바른 일을하기 위해 여기에 try / catch를하는 것이 좋습니다 (내 대답의 첫 부분을 다시 참조하십시오).

그래서, 당신이 보여주는 것처럼 try / catch를 “패턴”으로 사용합니다; 아직 좋은 생각이 아닙니다. 그리고 예, 충돌 을 방지합니다 . 그러나 모든 종류의 “정의되지 않은”동작으로 이어집니다. 알다시피, 예외를 제대로 처리하는 대신 그냥 잡을 때 ; 당신은 벌레 캔을 엽니 다. 나중에 이해하지 못하는 수많은 후속 오류가 발생할 수 있기 때문 입니다. 이전에 “근본 원인”이벤트를 사용했기 때문입니다. 어딘가에 인쇄했습니다. 그리고 그 어딘가 는 이제 사라졌습니다.


답변

로부터 안드로이드 문서 :

다음과 같이 자격을 부여합시다.

일반 예외를 포착하지 마십시오

예외를 잡을 때 게으르고 다음과 같이하는 것도 유혹이 될 수 있습니다.

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!
}

거의 모든 경우에 일반 Exception또는 Throwable 을 포착하는 것은 부적절합니다 (오류 예외를 포함하므로 Throwable이 바람직하지 않음). 당신이 (를 포함하여 예상 결코 예외 의미하기 때문에 매우 위험하다 RuntimeExceptions처럼이 ClassCastException) 응용 프로그램 수준 오류 처리에 잡힐.

이는 코드의 오류 처리 속성을 모호 Exception하게 만듭니다. 즉, 호출하는 코드에 누군가 새로운 유형을 추가 하면 컴파일러가 오류를 다르게 처리해야한다는 사실을 깨닫는 데 도움이되지 않습니다 .

일반 예외 포착에 대한 대안 :

  • 한 번의 시도 후 각 예외를 개별 catch 블록으로 개별적으로 catch합니다. 이것은 어색 할 수 있지만 모든 예외를 포착하는 것보다 여전히 바람직합니다.
    저자에 의한 편집 : 이것은 내 선택입니다. catch 블록에서 너무 많은 코드를 반복하지 않도록주의하십시오. Java 7 이상을 사용하는 경우 동일한 catch 블록이 반복되지 않도록 multi-catch를 사용하십시오.
  • 다중 try 블록을 사용하여 더 세분화 된 오류 처리를 갖도록 코드를 리팩터링합니다 . 구문 분석에서 IO를 분리하고 각 경우에 개별적으로 오류를 처리합니다.
  • 예외 다시 던지기 시킵니다. 어쨌든이 수준에서 예외를 잡을 필요가없는 경우가 많습니다. 메소드가 예외를 던지도록하십시오.

대부분의 경우 다른 유형의 예외를 동일한 방식으로 처리해서는 안됩니다.

이 답변의 출처에서 서식 / 단락을 약간 수정했습니다.

PS 예외를 두려워하지 마십시오 !! 그 사람들은 친구들이에요!!!


답변

나는 이것을 다른 답변에 대한 주석으로 넣을 것이지만 아직 그 명성이 없습니다.

당신은 그것이 나쁜 관행이라고 말하는 것이 맞습니다. 사실 당신이 게시 한 것은 예외와 관련하여 다른 유형의 나쁜 관행을 보여줍니다.

  1. 오류 처리 부족
  2. 일반 캐치
  3. 의도적 인 예외 없음
  4. 블랭킷 트라이 / 캐치

이 예를 통해 모든 것을 설명하려고합니다.

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

이는 다르게 처리해야하는 여러 가지 방법으로 실패 할 수 있습니다.

  1. 필드가 채워지지 않으므로 사용자에게 빈 화면이 표시되고 … 없음-오류 처리 부족.
  2. 인터넷 문제 또는 서버 자체 문제 (정지, 요청 중단, 전송 손상 등)와 같은 다양한 유형의 오류를 구분할 수 없습니다.-일반적인 캐치.
  3. 현재 시스템이이를 방해하기 때문에 자신의 목적으로 예외를 사용할 수 없습니다. -고의적 예외 없음
  4. 불필요한 오류 (예 : null.equals (…))로 인해 필수 코드가 실행되지 않을 수 있습니다. -블랭킷 트라이 / 캐치

솔루션

(1) 우선, 조용히 실패하는 것은 좋은 일이 아닙니다. 실패하면 앱이 작동하지 않습니다. 대신 문제 해결을 시도하거나 “사용자 데이터를로드 할 수 없습니다. 인터넷에 연결되어 있지 않습니까?”와 같은 경고를 표시해야합니다. 앱이 의도 한대로 작동하지 않는 경우 앱이 자동으로 닫히는 것보다 사용자에게 더 실망 스럽습니다.

(4) 사용자가 불완전한 경우, 예를 들어 국가를 알 수없고 null을 반환합니다. equals 메소드는 NullPointerException을 생성합니다. NPE가 위와 같이 그냥 던져지고 잡히면, 문제없이 실행될 수 있어도 fillFields (user) 메서드가 호출되지 않습니다. 널 검사를 포함하거나 실행 순서를 변경하거나 try / catch 범위를 조정하여이를 방지 할 수 있습니다. (또는 “us”.equals (user.getCountry ())와 같이 코딩을 저장할 수 있지만 예제를 제공해야했습니다). 물론 다른 예외는 fillFields ()가 실행되는 것을 방지하지만, 사용자가 없다면 어쨌든 실행하는 것을 원하지 않을 것입니다.

(1, 2, 3) 웹에서로드하면 종종 IOException에서 HttpMessageNotReadable 예외, 심지어 그냥 반환까지 다양한 예외가 발생합니다. 사용자가 인터넷에 연결되지 않았거나 백엔드 서버가 변경되었거나 다운되었을 수 있지만 catch (Exception)를 수행하기 때문에 알 수 없습니다. 대신 특정 예외를 잡아야합니다. 이런 식으로 여러 개를 잡을 수도 있습니다

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();
}

나는 그것이 그것을 설명하기를 바랍니다.

최소한 빠른 수정으로 할 수있는 일은 예외를 제외하고 백엔드에 이벤트를 보내는 것입니다. 예를 들어 firebase 또는 crashlytics를 통해. 이렇게하면 최소한 다음과 같은 것을 볼 수 있습니다 (예 : (4)와 같은 문제로 인해 사용자의 80 %가 주요 활동을로드하지 않습니다.


답변

확실히 나쁜 프로그래밍 관행입니다.

현재 시나리오에서 수백 개의 try catch 이와 같은 애플리케이션을 디버깅하지 않고 예외가 어디에서 발생하는지조차 알 수 없습니다. 애플리케이션이 프로덕션 환경에 있다면 악몽입니다.

그러나 로거를 포함하여 예외가 발생하는시기와 이유를 알 수 있습니다. 정상적인 작업 흐름은 변경되지 않습니다.

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


답변

이것은 나쁜 습관입니다. 다른 답변은 그렇게 말했지만 뒤로 물러서서 그 이유를 이해하는 것이 중요하다고 생각합니다. 애초에 예외가있는 를 .

모든 기능에는 사후 조건이 있습니다. 있습니다. 함수가 실행 된 후에는 모두 참이어야합니다. 예를 들어, 파일에서 읽는 함수에는 파일의 데이터를 디스크에서 읽어서 반환하는 게시 조건이 있습니다. 그러면 함수가 사후 조건 중 하나를 충족 할 수 없을 때 예외가 발생합니다.

함수에서 예외를 무시하면 (또는 단순히 예외를 로깅하여 효과적으로 무시하는 경우), 실제로 동의 한 모든 작업을 수행하지 않고 해당 함수에 대해 괜찮다고 말하는 것입니다. 이것은 가능성이없는 것 같습니다. 함수가 올바르게 실행되지 않으면 다음이 실행된다는 보장이 전혀 없습니다. 그리고 특정 함수가 완료되었는지 여부에 관계없이 나머지 코드가 제대로 실행되면 처음에 해당 함수가있는 이유가 궁금합니다.

[이제 빈 항목이 catch괜찮은 경우가 있습니다. 예를 들어, 로깅은 빈 캐치로 래핑하는 것을 정당화 할 수있는 것입니다. 일부 로깅을 작성할 수없는 경우에도 애플리케이션이 정상적으로 실행될 것입니다. 하지만 일반 앱에서 찾기 위해 정말 열심히 노력해야하는 특별한 경우입니다.]

요점은 실제로 앱을 계속 실행하지 않기 때문에 나쁜 습관입니다 (이 스타일에 대한 정당화). 기술적으로 OS가 그것을 죽이지 않았을 수도 있습니다. 그러나 단순히 예외를 무시한 후에도 앱이 여전히 제대로 실행될 가능성은 낮습니다. 그리고 최악의 경우 실제로 해를 끼칠 수 있습니다 (예 : 사용자 파일 손상 등).


답변

이것은 여러 가지 이유로 좋지 않습니다.

  1. 뭐하는거야 findViewById예외가 발생하는 ? 잡는 대신 그것을 고치십시오 (그리고 이것을 본 적이 없기 때문에 말하십시오).
  2. 잡히지 마 Exception특정 유형의 예외를 할 수있을 때 .
  3. 좋은 앱이 충돌하지 않는다는 믿음이 있습니다. 그건 사실이 아니야. 필요한 경우 좋은 앱이 충돌합니다.

앱이 잘못된 상태가되면 사용할 수없는 상태로 이동하는 것보다 충돌하는 것이 훨씬 좋습니다. NPE를 볼 때 null 수표를 고수하고 떠나서는 안됩니다. 더 나은 접근 방식은 무언가가 null 인 이유를 알아 내고 null이되는 것을 막거나 (null이 유효하고 예상되는 상태가되는 경우) null을 확인하는 것입니다. 그러나 처음에 문제가 발생하는 이유를 이해해야합니다.


답변

나는 지난 4-5 년 동안 안드로이드 앱을 개발해 왔으며 뷰 초기화를 위해 try catch를 사용한 적이 없습니다.

툴바가 이렇게하면

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

예 :-보기 (단편 / 대화 상자 / 모든 사용자 정의보기)에서 TextView를 얻으려면

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

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

이 대신

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

보기 개체는 실제보기 유형에 비해 최소 도달 범위가 있습니다.

참고 :-보기가로드 되었기 때문에 충돌 할 수 있습니다. 그러나 try catch를 추가하는 것은 나쁜 습관입니다.