TL; DR
전제
- 오류가 복구 불가능한 경우 런타임 예외가 발생해야합니다. 오류가 코드에 있고 외부 상태에 의존하지 않는 경우 (복구가 코드를 수정 함).
- 코드가 정확하지만 네트워크 연결이 없거나 파일을 찾을 수 없거나 손상된 등의 외부 상태가 예상되지 않은 경우 확인 된 예외가 발생해야합니다.
결론
전파 또는 인터페이스 코드가 기본 구현이 외부 상태에 따라 달라진다고 가정하는 경우 확인 된 예외를 런타임 예외로 다시 던질 수 있습니다.
이 절에서는 예외 중 하나가 발생해야하는시기에 대해 설명합니다. 결론에 대한 자세한 설명을 읽으려면 다음 가로 막대로 건너 뛸 수 있습니다.
런타임 예외를 발생시키는 것이 적절한시기는 언제입니까? 코드가 정확하지 않고 코드를 수정하여 복구가 적절한 경우 런타임 예외가 발생합니다.
예를 들어, 다음에 대한 런타임 예외를 발생시키는 것이 적절합니다.
float nan = 1/0;
이것은 제로 런타임 예외로 나누기를 던질 것입니다. 코드 에 결함이 있기 때문에 적합합니다 .
또는 예를 들어 다음은 HashMap
의 생성자 의 일부입니다 .
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
// more irrelevant code...
}
초기 용량 또는로드 팩터를 수정하려면 올바른 값이 전달되도록 코드를 편집하는 것이 적절합니다. 서버의 현재 상태, 디스크의 현재 상태, 파일 또는 다른 프로그램. 잘못된 인수로 호출되는 생성자는 호출 코드의 정확성에 따라 달라집니다. 잘못된 계산으로 인해 잘못된 매개 변수 또는 오류를 놓친 부적절한 흐름이 원인입니다.
확인 된 예외를 발생시키는 것이 언제 적절한가요? 코드를 변경하지 않고 문제 를 복구 할 수 있으면 확인 된 예외가 발생합니다 . 또는 다른 용어로 바꾸려면 코드가 올바른 동안 오류가 상태와 관련이있을 때 확인 된 예외가 발생합니다.
이제 "복구"라는 단어가 까다로울 수 있습니다. 목표를 달성하는 다른 방법을 찾을 수도 있습니다. 예를 들어 서버가 응답하지 않으면 다음 서버를 시도해야합니다. 이러한 종류의 복구가 가능하다면 훌륭하지만 복구가 의미하는 것은 아닙니다. 복구는 사용자에게 발생한 상황을 설명하는 오류 대화 상자를 표시하거나 서버 응용 프로그램 인 경우 복구가 가능할 수 있습니다 관리자에게 이메일을 보내거나 오류를 적절하고 간결하게 기록하기까지합니다.
mrmuggles의 답변에 언급 된 예를 들어 보겠습니다.
public void dataAccessCode(){
try{
..some code that throws SQLException
}catch(SQLException ex){
throw new RuntimeException(ex);
}
}
이것은 확인 된 예외를 처리하는 올바른 방법이 아닙니다. 이 방법의 범위 에서 예외를 처리 할 수 없다는 것만으로 앱이 중단되는 것은 아닙니다. 대신 다음과 같이 더 높은 범위로 전파하는 것이 적절합니다.
public Data dataAccessCode() throws SQLException {
// some code that communicates with the database
}
호출자가 복구 할 수있게합니다.
public void loadDataAndShowUi() {
try {
Data data = dataAccessCode();
showUiForData(data);
} catch(SQLException e) {
// Recover by showing an error alert dialog
showCantLoadDataErrorDialog();
}
}
확인 된 예외는 정적 분석 도구이므로 프로그래머가 구현을 배우거나 시행 착오 프로세스를 거치지 않아도 특정 호출에서 잘못 될 수있는 문제를 분명히합니다. 따라서 오류 흐름의 일부가 무시되지 않습니다. 점검 된 예외를 런타임 예외로 다시 던지는 것은이 노동 절약 정적 분석 기능에 대해 작동합니다.
또한 호출 계층은 위에서 설명한 것처럼 더 큰 사물 체계에 대한 더 나은 컨텍스트를 가지고 있음을 언급 할 가치가 있습니다. dataAccessCode
호출 되는 원인은 여러 가지 일 수 있으며 , 호출의 특정 이유는 호출자에게만 표시되므로 실패시 올바른 복구에서 더 나은 결정을 내릴 수 있습니다.
이제 우리는 이러한 차이점을 분명히 알았으므로 확인 된 예외를 런타임 예외로 다시 던져도 괜찮을 때 추론을 진행할 수 있습니다.
위에서 주어진 예외를 RuntimeException으로 다시 던지는 것이 언제 적절한가요? 사용중인 코드가 외부 상태에 대한 의존성을 가정하지만 외부 코드에 의존하지 않는다는 것을 분명히 주장 할 수 있습니다.
다음을 고려하세요:
StringReader sr = new StringReader("{\"test\":\"test\"}");
try {
doesSomethingWithReader(sr); // calls #read, so propagates IOException
} catch (IOException e) {
throw new IllegalStateException(e);
}
이 예제 IOException
에서 API는 Reader
외부 상태에 액세스하도록 설계되었으므로 코드가 전파 되고 있지만 StringReader
구현시 외부 상태에 액세스하지 않는다는 것을 알고 있습니다. 이 범위에서 우리는 호출에 관련된 부분이 IO 또는 다른 외부 상태에 액세스하지 않는다고 확신 할 수있는 구현 범위를 알지 못하는 동료를 놀라게하지 않고 예외를 런타임 예외로 안전하게 다시 던질 수 있습니다. IO 액세스 코드에서)가 발생한다고 가정합니다 IOException
.
외부 엄격히 의존 예외 상태로 유지하는 이유 확인은 그들이 (예측 코드의 버전마다 재생 될 것이다 논리 따라 예외 달리) 비 결정적이다. 예를 들어 0으로 나누려고하면 항상 예외가 발생합니다. 0으로 나누지 않으면 예외가 발생하지 않으며 예외가 발생하지 않기 때문에 해당 예외를 처리 할 필요가 없습니다. 그러나 파일에 액세스하는 경우 한 번 성공한다고해서 다음에 성공한다는 의미는 아닙니다. 사용자가 권한을 변경했거나 다른 프로세스가 파일을 삭제 또는 수정했을 수 있습니다. 따라서 항상 예외적 인 경우를 처리해야합니다. 그렇지 않으면 버그가있을 수 있습니다.