확인 및 확인되지 않은 예외를 선택하는시기


213

Java (또는 예외가 확인 된 다른 언어)에서 자체 예외 클래스를 만들 때 어떻게 확인해야하는지 여부를 어떻게 결정합니까?

내 본능은 호출자가 생산적인 방법으로 복구 할 수있는 경우에 검사 된 예외가 호출된다는 것입니다.


11
Barry Ruzek은 체크 또는 체크되지 않은 예외를 선택하는 방법에 대한 훌륭한 가이드 를 작성 했습니다 .
sigget

답변:


241

점검 된 예외는 언제 사용해야하는지 이해하는 한 훌륭합니다. Java 코어 API가 SQLException (때로는 IOException)에 대한 이러한 규칙을 따르지 않으므로 끔찍합니다.

검사 예외 를 사용해야 예측 하지만, 예방할 수 있는 오류 를 복구하는 것이 합리적 .

다른 모든 항목에는 검사되지 않은 예외를 사용해야합니다.

대부분의 사람들이 이것이 의미하는 바를 오해하기 때문에이 문제를 해결해 드리겠습니다.

  1. 예측 가능하지만 예측 불가능 : 호출자가 입력 매개 변수의 유효성을 검증하기 위해 자신의 권한 내에서 모든 작업을 수행했지만 제어 외부의 일부 조건으로 인해 작업이 실패했습니다. 예를 들어 파일을 읽으려고하지만 파일이 존재하는지 확인한 시간과 읽기 작업이 시작되는 시간 사이에 누군가 파일을 삭제합니다. 확인 된 예외를 선언하면 호출자에게이 실패를 예상하도록 지시합니다.
  2. 복구의 합리적 : 호출자에게 복구 할 수없는 예외를 예상하도록 지시하는 것은 의미가 없습니다. 사용자가 존재하지 않는 파일에서 읽으려고하면 호출자는 새 파일 이름을 입력하라는 메시지를 표시 할 수 있습니다. 반면에, 프로그래밍 버그 (유효하지 않은 메소드 인수 또는 버그가있는 메소드 구현)로 인해 메소드가 실패하는 경우 애플리케이션이 실행 중 문제를 해결하기 위해 수행 할 수있는 작업이 없습니다. 할 수있는 최선의 방법은 문제를 기록하고 개발자가 나중에 문제를 해결하기를 기다리는 것입니다.

던지는 예외 가 위의 모든 조건을 충족하지 않으면 검사되지 않은 예외를 사용해야합니다.

모든 수준에서 재평가 : 때때로 확인 된 예외를 포착하는 방법이 오류를 처리하기에 적합한 곳이 아닙니다. 이 경우 자신의 발신자에게 합리적인 것을 고려하십시오. 예외가 예측 가능하고, 예측 불가능하며, 복구하기에 합리적이라면 확인 된 예외를 직접 처리해야합니다. 그렇지 않은 경우, 점검되지 않은 예외로 예외를 랩해야합니다. 이 규칙을 따르면 사용중인 계층에 따라 확인 된 예외를 확인되지 않은 예외로 또는 그 반대로 변환 할 수 있습니다.

확인 된 예외와 확인되지 않은 예외 모두 올바른 추상화 수준을 사용하십시오 . 예를 들어, 두 개의 서로 다른 구현 (데이터베이스 및 파일 시스템)와 코드 저장소는 던져 구현 고유의 정보를 노출하지 않도록해야 SQLException하거나 IOException. 대신, 모든 구현 (예 :)에 걸친 추상화로 예외를 래핑해야합니다 RepositoryException.


2
"파일을 읽으려고하지만 파일이 존재하는지 확인하는 시간과 읽기 작업이 시작되는 시간 사이에 누군가 파일을 삭제합니다." => 이것은 어떻게 '예상'입니까? 나에게 그것은 다음과 같이 들린다 : 예상치 못하고 예방할 수있다. 누가 두 문장 사이에서 파일이 삭제 될 것이라고 누가 예상 할 것인가?
Koray Tugay

9
@KorayTugay Expected 는 시나리오가 일반적이라는 것을 의미하지 않습니다. 그것은 우리가이 오류를 미리 예측할 수 있다는 것을 의미합니다 (사전 예측할 수없는 프로그래밍 오류와 비교). 피할 수없는 것은 파일이 존재하는지 확인한 시간과 읽기 작업이 시작되는 시간 사이에 사용자 나 다른 응용 프로그램이 파일을 삭제하지 못하도록 프로그래머가 할 수있는 작업이 없다는 것을 말합니다.
길리

따라서 메소드 내의 데이터베이스 관련 문제가 확인 된 예외를 발생시켜야합니까?
ivanjermakov

59

에서 자바 학습자 :

예외가 발생하면 예외를 잡아서 처리하거나, 메소드가 해당 예외를 처리한다고 선언하여 처리 할 수 ​​없다고 컴파일러에 알려야합니다. 그러면 메소드를 사용하는 코드는 해당 예외를 처리해야합니다. 또한 예외를 처리 할 수없는 경우 예외가 발생한다고 선언하도록 선택할 수 있습니다).

컴파일러는 두 가지 중 하나 (캐치 또는 선언)를 수행했는지 확인합니다. 이를 검사 예외라고합니다. 그러나 컴파일러에서 오류 및 런타임 예외를 검사하지 않습니다 (필수 또는 선언하도록 선택할 수는 있지만). 따라서이 두 가지를 검사되지 않은 예외라고합니다.

오류는 시스템 충돌과 같이 응용 프로그램 외부에서 발생하는 조건을 나타내는 데 사용됩니다. 런타임 예외는 일반적으로 응용 프로그램 논리에서 오류로 발생합니다. 이 상황에서는 아무것도 할 수 없습니다. 런타임 예외가 발생하면 프로그램 코드를 다시 작성해야합니다. 따라서 이들은 컴파일러에서 확인하지 않습니다. 이러한 런타임 예외는 개발 및 테스트 기간에 공개됩니다. 그런 다음 이러한 오류를 제거하려면 코드를 리팩터링해야합니다.


13
이것이 정통적인 견해입니다. 그러나 그것에 대해 많은 논쟁이 있습니다.
artbristol

49

내가 사용하는 규칙은 확인되지 않은 예외를 사용하지 마십시오! (또는 당신이 주위에 어떤 방법도 보지 못할 때)

반대의 경우에는 매우 강력한 경우가 있습니다. 확인 된 예외를 사용하지 마십시오. 나는 토론에서 편견을 꺼려하지만 체크 된 예외를 도입하는 것이 뒤늦게 잘못된 결정이라는 광범위한 합의가있는 것 같습니다. 메신저를 쏘지 말고 주장을 참조하십시오 .


3
IMHO, 확인 된 예외는 특정 코드 블록에서 호출 된 메소드가 특정 예외 (또는 전혀)를 던질 것으로 기대하지 않는다고 선언하는 쉬운 방법이 있다면 확인 된 예외가 주요 자산이 될 수 있습니다. 그러한 기대와 상반되는 예외는 다른 예외 유형으로 싸서 다시 던져야합니다. 코드가 확인 된 예외에 대처할 준비가되지 않은 시간의 90 %는 그러한 줄 바꿈과 재 처리가 코드를 처리하는 가장 좋은 방법이지만 언어 지원이 없기 때문에 거의 수행되지 않습니다.
supercat

@supercat 본질적으로 그게 전부입니다 : 나는 엄격한 유형 검사의 열렬한 팬이며 확인 된 예외는 논리적 확장입니다. 나는 개념적으로 많은 것을 좋아하지만 확인 된 예외를 완전히 포기했습니다.
Konrad Rudolph

1
내가 설명 한 메커니즘으로 해결할 수있는 예외 디자인에 대한 한 가지 생각은 파일의 끝을지나 읽을 때 foo던지기로 문서화되고 예상하지 않더라도 던지는 메소드를 호출한다는 것입니다 . 호출하는 코드 는 파일의 끝에 도달했다고 생각하고 예기치 않은 일이 발생했다는 단서가 없습니다. 확인 된 예외 가장 유용 해야하는 상황이라고 생각 하지만 컴파일러가 처리되지 않은 확인 된 예외를 허용하는 유일한 경우이기도합니다. barExceptionfoobarExceptionfoofoo
supercat

@supercat : 첫 번째 주석에서 원하는 코드를 쉽게 수행 할 수있는 방법이 이미 있습니다. try 블록에서 코드를 랩핑하고 예외를 포착 한 다음 RuntimeException에서 예외를 랩핑하고 다시 throw하십시오.
Warren Dew

1
@KonradRudolph supercat은 "특정 코드 블록"을 나타냅니다. 블록을 정의해야하는 경우 선언적 구문은 팽창을 크게 줄이지 않습니다. 전체 기능에 대해 선언적이라고 생각한다면 잠재적으로 잡힌 확인 된 예외를 실제로 보지 않고 선언을 고수하고 더 좋은 방법이 없는지 확인하기 때문에 나쁜 프로그래밍을 장려 할 것입니다 그들을 처리합니다.
Warren Dew

46

여러 계층이있는 충분히 큰 시스템에서 예외를 처리하는 방법을 처리하기위한 아키텍처 수준 전략이 필요하기 때문에 확인 된 예외는 쓸모가 없습니다 (장애 장벽 사용).

예외를 확인하면 오류 처리 상태가 미세 관리되며 모든 대형 시스템에서 견딜 수 없습니다.

API 호출자가 어떤 계층에 있는지 알지 못하기 때문에 대부분의 경우 오류가 "복구 가능한"것인지 알 수 없습니다.

정수의 문자열 표현을 Int로 변환하는 StringToInt API를 작성한다고 가정 해 봅시다. "foo"문자열로 API를 호출하면 확인 된 예외를 처리해야합니까? 복구가 가능합니까? 그의 계층에서 내 StringToInt API의 호출자가 이미 입력의 유효성을 검사했을 수 있으므로이 예외가 발생하면 버그 또는 데이터 손상 이며이 계층에서 복구 할 수 없기 때문에 모르겠습니다.

이 경우 API 호출자는 예외를 포착하지 않습니다. 그는 예외를 "거품"으로 만들고 싶어합니다. 확인 된 예외를 선택하면이 호출자는 예외를 인위적으로 다시 던지기 위해 쓸모없는 캐치 블록을 많이 갖게됩니다.

복구 가능한 것은 대부분 API 작성기에 의존하지 않고 API 호출자에 따라 다릅니다. 확인되지 않은 예외 만 예외를 포착하거나 무시하도록 선택할 수 있으므로 API는 확인 된 예외를 사용해서는 안됩니다.



16
@alexsmail 인터넷은 나를 놀라게하지 않습니다, 실제로 그것은 내 블로그입니다 :)
Stephane

30

당신은 맞습니다.

검사되지 않은 예외 는 시스템이 빠르게 실패 하도록하는 데 사용됩니다 . 제대로 작동하려면 방법이 무엇인지 명확하게 기술해야합니다. 이 방법으로 입력을 한 번만 확인할 수 있습니다.

예를 들어 :

/**
 * @params operation - The operation to execute.
 * @throws IllegalArgumentException if the operation is "exit"
 */
 public final void execute( String operation ) {
     if( "exit".equals(operation)){
          throw new IllegalArgumentException("I told you not to...");
     }
     this.operation = operation; 
     .....  
 }
 private void secretCode(){
      // we perform the operation.
      // at this point the opreation was validated already.
      // so we don't worry that operation is "exit"
      .....  
 }

예를 들어 보자. 요점은 시스템이 빨리 실패하면 어디에서 왜 실패했는지 알 수 있습니다. 다음과 같은 스택 추적이 나타납니다.

 IllegalArgumentException: I told you not to use "exit" 
 at some.package.AClass.execute(Aclass.java:5)
 at otherPackage.Otherlass.delegateTheWork(OtherClass.java:4569)
 ar ......

그리고 당신은 무슨 일이 있었는지 알게 될 것입니다. "delegateTheWork"메소드 (4569 행)의 OtherClass는 클래스가 "exit"값으로 클래스를 호출했습니다.

그렇지 않으면 코드 전체에 유효성 검사를 뿌려야하며 오류가 발생하기 쉽습니다. 또한, 무엇이 잘못되었는지 추적하기가 어려우며 몇 시간 동안 디버깅에 어려움을 겪을 수 있습니다

NullPointerExceptions에서도 마찬가지입니다. 약 15 개의 메소드가있는 700 개의 라인 클래스가 있고 30 개의 속성을 사용하고 널 (null)이 될 수없는 경우, 각 메소드에서 널 입력 가능 여부를 유효성 검증하는 대신 모든 속성을 읽기 전용으로 만들고 생성자에서 유효성을 검증 할 수 있습니다. 공장 방법.

 public static MyClass createInstane( Object data1, Object data2 /* etc */ ){ 
      if( data1 == null ){ throw NullPointerException( "data1 cannot be null"); }

  }


  // the rest of the methods don't validate data1 anymore.
  public void method1(){ // don't worry, nothing is null 
      ....
  }
  public void method2(){ // don't worry, nothing is null 
      ....
  }
  public void method3(){ // don't worry, nothing is null 
      ....
  }

확인 된 예외 프로그래머 (귀하 또는 동료)가 모든 것을 올바르게 수행하고, 입력을 검증하고, 테스트를 실행했으며, 모든 코드가 완벽하지만 코드가 다운 (또는 파일 일 수있는) 타사 웹 서비스에 연결되어있을 때 유용합니다. 다른 외부 프로세스 등에 의해 삭제되었습니다). 연결을 시도하기 전에 웹 서비스의 유효성을 검사 할 수도 있지만 데이터 전송 중에 문제가 발생했습니다.

이 시나리오에서는 귀하 또는 동료가이를 도울 수있는 방법이 없습니다. 그러나 여전히 당신은 무언가를해야하고 응용 프로그램이 사용자의 눈에 죽고 사라지지 않도록해야합니다. 확인 된 예외를 사용하고 예외를 처리합니다. 대부분의 경우 오류를 기록하고 작업을 저장하고 (앱 작업) 사용자에게 메시지를 표시하려고합니다. . (사이트 blabla가 다운되었으므로 나중에 다시 시도하십시오.)

확인 된 예외가 과도하게 사용되면 (모든 메소드 서명에 "예외 예외"를 추가하여) 모든 사람이 해당 예외를 무시하고 (너무 일반적이기 때문에) 코드 품질이 심각해지기 때문에 코드가 매우 취약 해집니다. 타협.

확인되지 않은 예외를 과도하게 사용하면 비슷한 일이 발생합니다. 해당 코드의 사용자는 무언가 잘못 될 수 있는지 알지 못하고 많은 try {...} catch (Throwable t)가 나타납니다.


2
잘했다! +1. 그것은 항상이 구별 호출자 (체크되지 않은) / callee (체크 된)가 더 명확하지 않다는 것을 놀라게합니다 ...
VonC

19

여기 내 '최종 엄지 손가락 규칙'이 있습니다.
나는 사용한다:

  • 호출자로 인한 실패에 대한 내 메소드 코드 내에서 확인되지 않은 예외 ( 명확하고 완전한 문서가 포함됨 )
  • 내 코드를 사용하려는 사람에게 명시 적으로 명시 해야하는 수신자 로 인한 실패에 대한 예외확인 했습니다.

이전 답변과 비교할 때, 이것은 하나 또는 다른 (또는 두 가지) 종류의 예외 사용에 대한 명확한 이론적 근거입니다 (하나는 동의하거나 동의하지 않을 수 있음).


두 예외 모두에서, NullPointerException과 같은 매우 일반적인 검사되지 않은 예외를 제외하고 내 응용 프로그램에 대해 자체 검사되지 않은 검사 예외를 생성합니다 ( 여기에서 언급 한 모범 사례 ).

예를 들어 아래의이 특정 기능의 목적은 객체를 만드는 것 (또는 이미 존재하는 경우)을
의미하는 것입니다.

  • 만들거나 얻는 객체의 컨테이너가 있어야합니다 (CALLER
    => 검사되지 않은 예외 에 대한 책임 ,이 호출 된 함수에 대한 javadoc 주석 지우기)
  • 다른 매개 변수는 널
    ( null) 일 수 없습니다 (코더가이를 호출자에 놓도록 선택하십시오. 코더는 널 매개 변수를 검사하지 않지만 코더는 IT 문서를 처리 함)
  • 결과는 NULL이 될 수 없습니다 (수취인
    의 코드에 대한 책임과 선택, 호출자에게 큰 관심을 가질
    선택 => 검사 예외는 모든 호출자가 객체를 만들거나 찾을 수없는 경우 결정을 내려야하기 때문에 반드시 결정해야합니다. 결정은 컴파일시에 적용해야합니다 그들은이와 의미,이 가능성을 처리 할 필요없이이 기능을 사용할 수 없습니다 확인 ) 예외입니다.

예:


/**
 * Build a folder. <br />
 * Folder located under a Parent Folder (either RootFolder or an existing Folder)
 * @param aFolderName name of folder
 * @param aPVob project vob containing folder (MUST NOT BE NULL)
 * @param aParent parent folder containing folder 
 *        (MUST NOT BE NULL, MUST BE IN THE SAME PVOB than aPvob)
 * @param aComment comment for folder (MUST NOT BE NULL)
 * @return a new folder or an existing one
 * @throws CCException if any problems occurs during folder creation
 * @throws AssertionFailedException if aParent is not in the same PVob
 * @throws NullPointerException if aPVob or aParent or aComment is null
 */
static public Folder makeOrGetFolder(final String aFoldername, final Folder aParent,
    final IPVob aPVob, final Comment aComment) throws CCException {
    Folder aFolderRes = null;
    if (aPVob.equals(aParent.getPVob() == false) { 
       // UNCHECKED EXCEPTION because the caller failed to live up
       // to the documented entry criteria for this function
       Assert.isLegal(false, "parent Folder must be in the same PVob than " + aPVob); }

    final String ctcmd = "mkfolder " + aComment.getCommentOption() + 
        " -in " + getPNameFromRepoObject(aParent) + " " + aPVob.getFullName(aFolderName);

    final Status st = getCleartool().executeCmd(ctcmd);

    if (st.status || StringUtils.strictContains(st.message,"already exists.")) {
        aFolderRes = Folder.getFolder(aFolderName, aPVob);
    }
    else {
        // CHECKED EXCEPTION because the callee failed to respect his contract
        throw new CCException.Error("Unable to make/get folder '" + aFolderName + "'");
    }
    return aFolderRes;
}

19

예외로부터 복구하는 능력의 문제가 아닙니다. 제 생각에 가장 중요한 것은 호출자가 예외를 잡는 데 관심이 있는지 여부입니다.

다른 곳에서 사용할 라이브러리 또는 응용 프로그램의 하위 수준 계층을 작성하는 경우 호출자가 예외를 포착 (알고 있음)하는 데 관심이 있는지 자문 해보십시오. 그렇지 않은 경우 검사되지 않은 예외를 사용하므로 불필요하게 부담을주지 않습니다.

이것은 많은 프레임 워크에서 사용되는 철학입니다. 특히 봄과 최대 절전 모드는 확인 된 예외가 Java에서 과도하게 사용되기 때문에 알려진 확인 된 예외를 확인되지 않은 예외로 정확하게 변환합니다. 내가 생각할 수있는 한 가지 예는 json.org의 JSONException입니다.

그건 그렇고, 예외에 대한 호출자의 관심은 대부분 예외에서 회복하는 능력과 직접적으로 관련이 있지만 항상 그런 것은 아닙니다.


13

다음은 Checked / Checked 딜레마에 대한 매우 간단한 솔루션입니다.

규칙 1 : 검사되지 않은 예외는 코드가 실행되기 전에 테스트 가능한 조건으로 생각하십시오. 예를 들어…

x.doSomething(); // the code throws a NullPointerException

여기서 x는 null입니다 ... ... 코드는 다음과 같아야합니다.

if (x==null)
{
    //do something below to make sure when x.doSomething() is executed, it won’t throw a NullPointerException.
    x = new X();
}
x.doSomething();

규칙 2 : Checked Exception을 코드가 실행되는 동안 발생할 수있는 테스트 할 수없는 조건으로 생각하십시오.

Socket s = new Socket(“google.com”, 80);
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();

… 위의 예에서 DNS 서버가 다운되어 URL (google.com)을 사용하지 못할 수 있습니다. DNS 서버가 작동하는 순간에도 'google.com'이름을 IP 주소로 확인했지만 google.com에 연결하면 언제든지 네트워크가 다운 될 수 있습니다. 스트림을 읽고 쓰기 전에 항상 네트워크를 테스트 할 수는 없습니다.

문제가 있는지 알기 전에 코드를 간단히 실행해야하는 경우가 있습니다. Checked Exception을 통해 이러한 상황을 처리하도록 개발자가 코드를 작성하도록 강요함으로써이 개념을 고안 한 Java 제작자에게 모자를 기울여야합니다.

일반적으로 Java의 거의 모든 API는 위의 두 가지 규칙을 따릅니다. 파일에 쓰려고하면 쓰기가 완료되기 전에 디스크가 가득 찰 수 있습니다. 다른 프로세스로 인해 디스크가 가득 찼을 수 있습니다. 이 상황을 테스트하는 방법은 없습니다. 언제든 하드웨어 사용이 실패 할 수있는 하드웨어와 상호 작용하는 사람들에게는 Checked Exceptions가이 문제에 대한 우아한 해결책 인 것 같습니다.

이것에 회색 영역이 있습니다. 많은 테스트가 필요한 경우 (&&와 ||가 많은 if 문이 부풀어 오르는 경우) 예외가 발생하기 때문에 CheckedException이 예외로 발생합니다.이 문제는 말할 수 없습니다. 프로그래밍 오류입니다. 10 개 미만의 테스트가있는 경우 (예 : 'if (x == null)') 프로그래머 오류는 UncheckedException이어야합니다.

언어 통역사를 다룰 때 상황이 흥미로워집니다. 위의 규칙에 따라 구문 오류를 검사 또는 검사되지 않은 예외로 간주해야합니까? 언어의 구문을 실행하기 전에 테스트 할 수 있으면 UncheckedException이어야한다고 주장합니다. 개인 컴퓨터에서 어셈블리 코드가 실행되는 방식과 유사하게 언어를 테스트 할 수없는 경우 구문 오류는 확인 된 예외 여야합니다.

위의 두 가지 규칙은 선택해야 할 문제의 90 %를 제거 할 것입니다. 규칙을 요약하려면이 패턴을 따르십시오. 1) 실행할 코드를 올바르게 실행하기 전에 코드를 테스트 할 수 있고 예외가 발생하는 경우 (예 : 프로그래머 오류) 예외는 UncheckedException (RuntimeException의 하위 클래스)이어야합니다. ). 2) 실행될 코드를 올바르게 실행하기 전에 테스트 할 수없는 경우 예외는 검사 예외 (예외의 하위 클래스) 여야합니다.


9

이를 점검 또는 점검되지 않은 예외라고 할 수 있습니다. 그러나 프로그래머가 가지 유형의 예외를 모두 포착 할 수 있으므로 가장 좋은 대답은 모든 예외를 선택하지 않은 상태로 작성 하고 문서화하십시오. 그렇게하면 API를 사용하는 개발자가 예외를 포착하고 무언가를 수행 할 것인지 선택할 수 있습니다. 확인 된 예외는 모든 시간을 낭비하는 것이며 코드를 볼 때 충격적인 악몽이됩니다. 그러면 적절한 단위 테스트를 통해 무언가를 잡아서 수행해야 할 예외가 발생합니다.


1
+1 단위 테스트가 문제를 해결하는 더 좋은 방법 일 수 있다는 점을 언급했습니다. 예외는 해결하려고합니다.
키스 핀슨

단위 테스트의 경우 +1 Checked / Uncheked 예외를 사용하면 코드 품질에 거의 영향을 미치지 않습니다. 따라서 검사 된 예외를 사용하면 코드 품질이 향상된다는 주장은 완전한 가짜 주장입니다!
user1697575

7

확인 된 예외 : 클라이언트가 예외에서 복구 할 수 있고 계속하려면 확인 된 예외를 사용하십시오.

확인되지 않은 예외 : 클라이언트가 예외 후에 아무 작업도 수행 할 수 없으면 검사되지 않은 예외가 발생합니다.

예 : A () 메서드에서 산술 연산을 수행하고 A ()의 출력을 기반으로 산술 연산을 수행해야하는 경우 다른 연산을 수행해야합니다. 런타임 중에 예상하지 않은 메소드 A ()의 출력이 널인 경우 런타임 예외 인 널 포인터 예외를 처리해야합니다.

여기를 참조 하십시오


2

특히 API를 디자인 할 때 확인되지 않은 예외에 대한 기본 설정에 동의합니다. 호출자는 항상 문서화되고 확인되지 않은 예외를 포착하도록 선택할 수 있습니다. 불필요하게 발신자를 강요 할 필요는 없습니다.

확인 된 예외는 구현 세부 정보로 하위 수준에서 유용하다는 것을 알았습니다. 지정된 오류 "반환 코드"를 관리하는 것보다 더 나은 제어 메커니즘의 흐름 인 것 같습니다. 때로는 저수준 코드 변경에 대한 아이디어의 영향을 보는 데 도움이 될 수 있습니다 ... 하류에서 확인 된 예외를 선언하고 조정해야 할 사람을 찾으십시오. catch (Exception e) 또는 일반적으로 너무 잘 생각되지 않는 Exception던지는 일반적인 점이 많으면이 마지막 점은 적용되지 않습니다 .


2

수년간의 개발 경험을 쌓은 후 저의 의견을 나누고 자합니다.

  1. 확인 된 예외. 이것은 비즈니스 유스 케이스 또는 통화 흐름의 일부이며, 우리가 기대하거나 기대하지 않는 애플리케이션 로직의 일부입니다. 예를 들어, 연결이 거부되고 조건이 충족되지 않습니다. 우리는이를 처리하고 사용자에게 발생 된 사항과 다음에 수행 할 작업 (나중에 다시 시도 할 사항)을 지시하는 해당 메시지를 표시해야합니다. 나는 보통이를 사후 처리 예외 또는 "사용자"예외라고 부릅니다.

  2. 확인되지 않은 예외. 이것은 프로그래밍 예외의 일부이며 소프트웨어 코드 프로그래밍 (버그, 결함)에서 실수로 프로그래머가 설명서에 따라 API를 사용해야하는 방식을 반영합니다. 외부 lib / framework doc에 따르면 NPE 또는 IllegalArgumentException이 발생하기 때문에 일부 범위의 데이터를 가져오고 null이 아닌 것으로 예상하면 프로그래머는이를 예상하고 설명서에 따라 API를 올바르게 사용해야합니다. 그렇지 않으면 예외가 발생합니다. 나는 보통 전처리 예외 또는 "유효성 검사"예외라고 부른다.

대상 고객 별 이제 예외가 설계된 대상 독자 또는 사람들 그룹에 대해 이야기 해 봅시다 (내 의견에 따라).

  1. 확인 된 예외. 대상 고객은 사용자 / 클라이언트입니다.
  2. 확인되지 않은 예외. 대상 독자는 개발자입니다. 다시 말해, 확인되지 않은 예외는 개발자만을위한 것입니다.

응용 프로그램 개발 수명주기 단계

  1. 확인 된 예외는 전체 생산 수명주기 동안 애플리케이션이 예외적 인 경우를 처리하는 정상적이고 예상되는 메커니즘으로 존재하도록 설계되었습니다.
  2. 확인되지 않은 예외는 응용 프로그램 개발 / 테스트 수명주기 동안 만 존재하도록 설계되었으며, 해당 시간 동안 모두 수정해야하며 응용 프로그램이 이미 프로덕션 환경에서 실행될 때 발생해서는 안됩니다.

프레임 워크가 일반적으로 검사되지 않은 예외를 사용하는 이유 (예 : 봄)는 프레임 워크가 애플리케이션의 비즈니스 로직을 판별 할 수 없기 때문에 개발자가 자신의 로직을 파악하고 디자인해야합니다.


2

프로그래머 오류인지 아닌지에 따라이 두 가지 유형의 예외를 구별해야합니다.

  • 오류가 프로그래머 오류 인 경우 검사되지 않은 예외 여야합니다 . 예를 들면 다음과 같습니다. SQLException / IOException / NullPointerException. 이러한 예외는 프로그래밍 오류입니다. 프로그래머가 처리해야합니다. JDBC API에서 SQLException은 검사 예외이며 Spring JDBCTemplate에서는 검사되지 않은 예외입니다 .Spring을 사용할 때 프로그래머는 SqlException에 대해 걱정하지 않습니다.
  • 오류가 프로그래머 오류가 아니고 외부에서 발생한 이유 인 경우 검사 예외 여야합니다. 예를 들어, 파일이 삭제되거나 다른 사람이 파일 권한을 변경 한 경우 복구해야합니다.

FileNotFoundException은 미묘한 차이점을 이해하는 좋은 예입니다. 파일을 찾을 수없는 경우 FileNotFoundException이 발생합니다. 이 예외에는 두 가지 이유가 있습니다. 파일 경로가 개발자에 의해 정의되거나 GUI를 통해 최종 사용자로부터 가져 오는 경우 검사되지 않은 예외 여야합니다. 다른 사람이 파일을 삭제 한 경우 검사 된 예외 여야합니다.

Checked Exception은 두 가지 방법으로 처리 할 수 ​​있습니다. 이들은 try-catch를 사용하거나 예외를 전파합니다. 예외가 전파되는 경우 예외 처리로 인해 호출 스택의 모든 메소드가 밀접하게 연결 됩니다. 따라서 Checked Exception을 신중하게 사용해야합니다.

계층화 된 엔터프라이즈 시스템을 개발하는 경우 대부분 검사되지 않은 예외를 선택해야하지만 아무것도 할 수없는 경우 검사 예외를 사용하는 것을 잊지 마십시오.


1

확인 된 예외는 호출자에게 정보를 제공하려는 복구 가능한 경우 (예 : 불충분 한 권한, 파일을 찾을 수 없음 등)에 유용합니다.

검사되지 않은 예외는 런타임 동안 사용자 나 프로그래머에게 심각한 오류나 예기치 않은 조건을 알리기 위해 거의 사용되지 않습니다. 다른 사람이 사용할 코드 나 라이브러리를 작성하는 경우 컴파일러에서 검사되지 않은 예외가 발생하지 않을 수 있으므로 컴파일러에서 예외를 포착하거나 선언하지 않기 때문에 예외를 던지지 마십시오.


"확인되지 않은 예외는 거의 사용되지 않는 경우가 거의 없습니다"라는 말에 동의하지 않습니다. 응용 프로그램 예외 계층을 디자인 할 때는 기본적으로 확인되지 않은 exceprions를 사용하십시오. 개발자가 예외를 처리 할 시점을 결정하도록하십시오 (예 : 처리 방법을 모르는 경우 catch 블록 또는 put throws 절을 강요하지 않아야 함).
user1697575

1

예외가 예상되지 않을 때마다이를 잡은 후에도 진행할 수 있으며 예외를 피하기 위해 아무것도 할 수 없으며 확인 된 예외를 사용할 수 있습니다.

특정 예외가 발생했을 때와 그 예외가 예상되지만 확실하지 않을 때 의미있는 일을하고 싶을 때마다 확인 된 예외를 사용할 수 있습니다.

다른 계층에서 예외를 탐색 할 때마다 모든 계층에서 예외를 포착 할 필요는 없습니다.이 경우 런타임 예외 또는 랩 예외를 검사되지 않은 예외로 사용할 수 있습니다.

런타임 예외는 예외가 발생할 가능성이 가장 높고 더 이상 진행할 방법이없고 복구 할 수없는 경우에 사용됩니다. 따라서이 경우 해당 예외와 관련하여 예방 조치를 취할 수 있습니다. 예 : NUllPointerException, ArrayOutofBoundsException. 이런 일이 더 일어날 가능성이 높습니다. 이 시나리오에서는 이러한 예외를 피하기 위해 코딩하는 동안 예방 조치를 취할 수 있습니다. 그렇지 않으면 모든 곳에서 try catch 블록을 작성해야합니다.

보다 일반적인 예외는 선택하지 않고 덜 일반적으로 확인할 수 있습니다.


1

몇 가지 질문에서 예외에 대해 생각할 수 있다고 생각합니다.

왜 집행이 발생합니까? 일어날 때 우리는 무엇을 할 수 있습니까

실수로 버그입니다. null 객체의 메소드 등이 호출됩니다.

String name = null;
... // some logics
System.out.print(name.length()); // name is still null here

이러한 종류의 예외는 테스트 중에 수정해야합니다. 그렇지 않으면 생산이 중단되고 즉시 수정 해야하는 매우 높은 버그가 발생합니다. 이런 종류의 예외는 확인할 필요가 없습니다.

외부로부터의 입력 으로 외부 서비스의 출력을 제어하거나 신뢰할 수 없습니다.

String name = ExternalService.getName(); // return null
System.out.print(name.length());    // name is null here

여기서 널 (null) 일 때 계속하려면 이름이 널인지 여부를 확인해야합니다. 그렇지 않은 경우 이름을 그대로두면 여기에서 중지하고 호출자에게 런타임 예외를 제공합니다. 이런 종류의 예외는 확인할 필요가 없습니다.

외부의 런타임 예외로 인해 외부 서비스를 제어하거나 신뢰할 수 없습니다.

여기서는 계속 발생할 때 ExternalService에서 모든 예외를 잡아야 할 수도 있습니다. 그렇지 않으면 혼자 내버려두고 여기서 중지하고 호출자에게 런타임 예외를 제공합니다.

외부에서 예외를 확인 하면 외부 서비스를 제어하거나 신뢰할 수 없습니다.

여기서는 계속 발생할 때 ExternalService에서 모든 예외를 잡아야 할 수도 있습니다. 그렇지 않으면 혼자 내버려두고 여기서 중지하고 호출자에게 런타임 예외를 제공합니다.

이 경우 ExternalService에서 어떤 종류의 예외가 발생했는지 알아야합니까? 때에 따라 다르지:

  1. 어떤 종류의 예외를 처리 할 수 ​​있으면 예외를 잡아서 처리해야합니다. 다른 사람들을 위해 거품을 내십시오.

  2. 특정 실행에 대해 사용자에게 로그 또는 응답이 필요한 경우이를 포착 할 수 있습니다. 다른 사람들을 위해 거품을 내십시오.


0

Application Exception을 선언 할 때 Unchecked Exception, 즉 RuntimeException의 서브 클래스이어야한다고 생각합니다. 그 이유는 try-catch로 응용 프로그램 코드를 어지럽히 지 않고 메소드에서 선언을 던지기 때문입니다. 응용 프로그램이 Java Api를 사용하는 경우 어쨌든 처리 해야하는 확인 된 예외가 발생합니다. 다른 경우에는 응용 프로그램에서 확인되지 않은 예외가 발생할 수 있습니다. 애플리케이션 호출자가 여전히 점검되지 않은 예외를 처리해야하는 경우이를 수행 할 수 있습니다.


-12

내가 사용하는 규칙은 확인되지 않은 예외를 사용하지 마십시오! (또는 당신이 주위에 어떤 방법도 보지 못할 때)

라이브러리를 사용하는 개발자의 관점이나 라이브러리 / 응용 프로그램을 사용하는 최종 사용자의 관점에서 보지 못한 예외로 인해 충돌하는 응용 프로그램에 직면하게됩니다. 그리고 모든 것을 포괄하는 것도 좋지 않습니다.

이렇게하면 응용 프로그램이 완전히 사라지는 대신 최종 사용자에게 여전히 오류 메시지가 표시 될 수 있습니다.


1
대부분의 확인되지 않은 예외에 대해 포괄적으로 잘못 생각한다고 설명하지 않습니다.
Matthew Flaschen

논증되지 않은 답변에 완전히 동의하지 않음 : "확인되지 않은 예외는 사용하지 마십시오"
user1697575
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.