안전하고 읽을 수있는 방식으로 절대 던질 수없는 IOException을 어떻게 처리 할 수 ​​있습니까?

StackOverflow https://stackoverflow.com/questions/1045829

문제

"잘못 될 수있는 것과 잘못 될 수없는 것의 주요 차이점은 잘못 될 수없는 일이 잘못 될 때 일반적으로 수리하거나 수리하는 것이 불가능하다는 것입니다." -더글러스 애덤스

수업 파일이 있습니다. FileItems 생성자는 파일을 가져 와서 파일이 존재하지 않으면 예외 (filenotfoundException)를 던졌습니다. 해당 클래스의 다른 방법에는 파일 작업이 포함되므로 FilenotFoundException을 던지는 능력이 있습니다. 더 나은 솔루션을 찾고 싶습니다. 다른 프로그래머가 이러한 모든 필수 불가능한 모든 것을 처리 할 필요가없는 솔루션.

문제의 사실 :

  1. 파일은 존재하는 것으로 확인되었지만 현실의 일부 주요 결함을 통해이 메소드가 호출되기 전에 파일이 삭제 될 수있는 가능성이 거의 없습니다.
  2. 1이 발생할 확률은 극히 다르고 복구 할 수 없으므로 확인되지 않은 예외를 정의하는 것이 좋습니다.
  3. 파일은 이미 존재하는 것으로 밝혀졌으며, 다른 프로그래머가 코드를 작성하고 확인 된 filenotfoundException을 잡아야합니다. 지루하고 쓸모없는 것 같습니다. 프로그램은 그 시점에서 완전히 실패해야합니다. 예를 들어, 컴퓨터가 할 가능성은 항상 있습니다. 불을 붙잡 으십시오. 그러나 다른 프로그래머가 검사 된 예외로 처리하도록 강요 할만 큼 미친 사람은 없습니다..
  4. 나는 때때로 이런 종류의 예외 문제를 해결하고,이 문제 (나의 오래된 솔루션)가 지루하고 Code-Bloat에 추가 될 때마다 확인되지 않은 예외를 정의합니다.

코드는 현재 다음과 같습니다

 public Iterator getFileItemsIterator() {
    try{
        Scanner sc = new Scanner(this.fileWhichIsKnowToExist);
        return new specialFileItemsIterator(sc);        
       } catch (FileNotFoundException e){ //can never happen} 

    return null;
 }

확인되지 않은 FilenotFoundException을 정의하지 않고 어떻게 더 잘 수행 할 수 있습니까? checkedException을 비 체크 인식에 시전 할 수있는 방법이 있습니까?

도움이 되었습니까?

해결책

이것을 다루는 일반적인 패턴은입니다 예외 체인. runtimeexception에서 filenotfoundException을 래핑합니다.

catch(FileNotFoundException e) {
    throw new RuntimeException(e);
}

이 패턴은 특정 상황 (예 : 예 : 예외)에서 예외가 발생할 수 없을 때뿐만 아니라 예외 (예 : 데이터베이스 링크 실패)를 처리 할 의도가 없을 때도 적용 할 수 있습니다.

편집하다:이 유사한 반란제를 조심하십시오.

catch(FileNotFoundException e) {
    throw new RuntimeException(e.getMessage());
}

이렇게하면 원래 스택 트레이스의 모든 중요한 정보를 버리면 종종 문제를 추적하기 어렵게 만듭니다.

다른 편집 : Thorbjørn Ravn Andersen이 그의 응답에서 올바르게 지적한 것처럼, 예외 메시지로서, 예외를 예외로 묶는 이유를 언급하는 것은 아프지 않습니다.

catch(FileNotFoundException e) {
    throw new RuntimeException(
        "This should never happen, I know this file exists", e);
}

다른 팁

확인 된 예외를 runtimexception 내부에 떼어 내면서 확인되지 않은 예외로 변환 할 수 있습니다. Stack에서 예외가 더 높아지고 PrintStackTrace ()를 사용하여 출력하면 원래 예외에 대한 스택도 표시됩니다.

try {
    // code...
}
catch (IOException e) {
    throw new RuntimeException(e);
}

이것은 좋은 해결책입니다. 이러한 상황에서 주저하지 말아야합니다.

양식 사용을 고려하십시오

throw new RuntimeException("This should never happen", e);

대신에. 이를 통해 코드를 읽을 때의 의미를 관리자에게 전달할 수 있지만 이상한 시나리오에서는 예외가 발생해야합니다.

편집 : 이것은 예외를 기대하지 않는 메커니즘을 통해 예외를 통과시키는 좋은 방법입니다. 예를 들어 "데이터베이스에서 더 많은 행을 얻는다"ITERATOR가있는 경우 반복자 인터페이스는 예를 들어 FILENOTFoundException을 던질 수 없으므로 이렇게 랩핑 할 수 있습니다. 반복자를 사용하는 코드에서 runtimeexception을 잡고 getCause ()로 원래 Excpetion을 검사 할 수 있습니다. 레거시 코드 경로를 살 때 매우 유용합니다.

귀하의 입장이 이것이 가능성이 높고 프로그램을 끝내야한다는 경우 기존 런타임 예외, runtimeexception 자체 (불법적 인 상태가 아닌 경우)를 사용하십시오.

try {
  ....

} catch (FileNotFoundException e) {
    throw new RuntimeException(e);
}

당신은 아마도 슈퍼 클래스를 던지는 것이 더 나을 것입니다. IOException 파일의 읽기 또는 쓰기와 관련된 코드의 어느 시점에서.

클래스의 생성자가 실행될 때 파일이 존재할 수 있지만이를 보장하지는 않습니다.

  1. 방법이 호출 될 때 존재합니다
  2. 쓰기 가능/읽을 수 있습니다
  3. 다른 스레드는 액세스하지 못하고 어떻게 든 스트림을 조입니다.
  4. 리소스는 처리 중에 사라지지 않습니다.

등.

휠을 재창조하는 대신 JDK/가 어디든지 IoException을 다시 줄입니다.java.io 강제를 사용하는 클래스.

또한 나는 그들의 생성자로부터 예외를 던지는 증오 수업에 대해 - 내가 당신이라면 이것을 제거 할 것입니다.

나는 약간의 인터넷 검색을 하고이 코드의 글로벌을 발견했습니다. 내가 생각하는 접근 방식이 조금 더 유연합니다.

이것의 칭찬 기사

class SomeOtherException extends Exception {}

public class TurnOffChecking {
  private static Test monitor = new Test();
  public static void main(String[] args) {
    WrapCheckedException wce = new WrapCheckedException();
    // You can call f() without a try block, and let
    // RuntimeExceptions go out of the method:
    wce.throwRuntimeException(3);
    // Or you can choose to catch exceptions:
    for(int i = 0; i < 4; i++)
      try {
        if(i < 3)
          wce.throwRuntimeException(i);
        else
          throw new SomeOtherException();
      } catch(SomeOtherException e) {
          System.out.println("SomeOtherException: " + e);
      } catch(RuntimeException re) {
        try {
          throw re.getCause();
        } catch(FileNotFoundException e) {
          System.out.println(
            "FileNotFoundException: " + e);
        } catch(IOException e) {
          System.out.println("IOException: " + e);
        } catch(Throwable e) {
          System.out.println("Throwable: " + e);
        }
      }
    monitor.expect(new String[] {
      "FileNotFoundException: " +
      "java.io.FileNotFoundException",
      "IOException: java.io.IOException",
      "Throwable: java.lang.RuntimeException: Where am I?",
      "SomeOtherException: SomeOtherException"
    });
  }
} ///:~

나는 같은 문제를 경험했다.

가장 간단한 경우 사용자에게 오류를 알리고 작업을 반복하거나 취소하도록 제안합니다.

일반적으로 워크 플로우는 일련의 행동 (I/O 포함)이며, 각 행동은 이전의 행동이 성공했다고 ""가정합니다.

내가 선택한 접근법은 '롤백'액션 목록을 만드는 것입니다. 워크 플로가 성공하면 무시됩니다. 예외가 발생하면 롤백을 실행하고 사용자에게 예외를 제시합니다.

이것:

  • 데이터의 무결성을 유지합니다
  • 훨씬 쉽게 코딩 할 수 있습니다

일반적인 기능은 다음과 같습니다.

returntype func(blah-blah-blah, Transaction tr)
{
    // IO example
    Stream s = null;
    try
    {
        s = new FileStream(filename);
        tr.AddRollback(File.Delete(filename));
    }
    finally
    {
        if (s != null)
            s.close();
    }
}

일반적인 사용은 다음과 같습니다.

Transaction tr = new Transaction();
try
{
    DoAction1(blah1, tr);
    DoAction2(blah2, tr);
    //...
}
catch (Exception ex)
{
    tr.ExecuteRollbacks();
    // queue the exception message to the user along with a command to repeat all the actions above
}

이것은 작은 실제 세계에서는 약간 까다 롭습니다

  • 때로는 실행 조치 전에 많은 자물쇠를 얻을 필요가 있습니다.
  • 롤백 코드는 예외적이어야합니다 (예 :

그러나 나는 이미이 접근법에 익숙해졌지만 이제 내 응용 프로그램이 더 안정적입니다.

전체 애플리케이션을 a로 탱크하지 마십시오 RuntimeException 오류 조건이 가능하지 않은 경우. RuntimeException 프로그래머 오류를 위해 예약해야합니다 IOException 프로그래머 오류로 인해 발생하지 않을 가능성이 높습니다.

대신, 더 높은 레벨 예외 및 재창조로 하위 레벨 예외를 캡슐화하십시오. 그런 다음 더 높은 레벨 예외를 통화 체인을 처리하십시오.

예를 들어:

class SomeClass {

  public void doActions() {
    try {
      someAction();
    } catch (HigherLevelException e) {
      notifyUser();
    }

    someOtherUnrelatedAction();
  }

  public void someAction() throws HigherLevelException {  
    try {
      // user lower-level abstraction to do our bidding
    } catch(LowerLevelException e) {
      throw new HigherLevelException(e);
    }
  }

  public void someOtherUnrelatedAction() {
    // does stuff
  }
}

아마도 예외를 던진 통화 스택은 응용 프로그램에서 일부 작업을 수행하는 것이었을 것입니다. 전체 애플리케이션이 a로 충돌하는 대신 RuntimeException 해당 작업 중에 문제가 발생할 때해야 할 일을 파악하십시오. 예를 들어, 파일을 저장하려고 했습니까? 충돌하지 말고 대신 사용자에게 문제가 있음을 알립니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top