1. 예외처리(Exception Handling)
Def) 예외: 컴파일도 되고 실행도 되지만 의도와 다른게 동작하는 것
1.1 프로그램 오류
- 컴파일 에러: 컴파일 시에 발생하는 에러 ex) system.out.println(); => 오류
- 런타임에러: 실행 시에 발생하는 에러
- 논리적 에러: 실행되지만, 의도와 다르게 동작하는 것
- 에러와 예외 차이
-> 에러: 코드에 의해 수습될 수 없는 심각한 오류
-> 예외: 코드로 수습할 정도의 미약한 오류(실행 잘 되지만 의도와 다르게 동작)
- 예외처리의 정의, 목적
Def) 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것
- 목적: 비정상 종료를 막고, 정상적 실행상태를 유지한다.
1.2 예외 클래스의 계층구도
- 모든 예외는 Exception(모든 예외의 최고 조상)의 자손 클래스
- checked예외: 컴파일러가 예외처리 여부를 체크(예외 처리(try-catch) 필수)
-> Exception클래스와 그 자손들, RuntimeException는 제외)
- unchecked예외: 컴파일러가 예외처리 여부를 체크하지 않는다 (예외 처리 선택) - (RuntimeException와 자손들)
- RuntimeException클래스들은 주로 프로그래머의 실수에 의해 발생될 수 있는 예외들이다.
- Exception클래스들은 주로 외부의 영향으로 발생할 수 있는 것들이다.
-> 주로 프로그램 사용자의 동작에 의해 발생한다.
1.3 예외처리하기 try - catch문
- 예외발생하면 이를 처리할 catch블럭을 찾아 내려간다.
- 일치하는 catch블럭을 찾지 못하면 예외는 처리되지 못한다.
- Exception 선언된 catch블럭은 맨 마지막 블럭.
Note) 하나의 try블럭 다음에는 여러 종류의 예외를 처리할 수 있도록 하나 이상의 catch블럭이 올 수 있다.
- 이 중에서 발생한 예외와 일치하는 단 한 개의 catch블럭만 수행된다.
- 일치하는 예외가 없으면 처리 되지 않는다.
- catch블럭 내에 또 다른 try-catch문이 포함된 경우에는 같은 이름의 참조변수를 사용할 수 없다.
1.5 예외발생과 catch블럭
- printStackTrace() : 예외발생 당시의 호출 스택(Call Stack)에 있었던 메서드의 정보와 예외 메시지를 출력
- getMessage() : 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.
- 멀티 catch블럭: 내용이 같은 catch블럭을 하나로 합친 것
1.6 예외 발생시키기
1) 먼저, 연산자 new를 이용해서 발생시키려는 예외 클래스의 객체를 만든다
2) 키워드 throw를 이용해서 예외를 발생시킨다.
Ex)
Note)

- 예외 발생시키는 두 줄을 간략히, throw new exception("고의로 발생시켰음."); 으로 나타낼 수 있다.
1.7 메서드에 예외 선언하기
- 메서드가 호출시 발생가능한 예외를 호출하는 쪽에 알리는 것
- 만일 위에 Exception만 선언하면 예외뿐만 아니라 자손타입의 예외까지도 발생할 가능성이 있다는 것이다.
- 오버라이딩 할 때는 선언된 예외의 개수가 아니라 상속관계까지 고려해야한다.
Ex)
Note) 실행 결과

- 프로그램의 실행도중 java.lang.Exception이 발생하여 비정상적으로 종료했다.
- 예외 발생했을 때의 호출 스택내용을 알 수 있다.
1) 예외가 발생했을 때, 모두 3개의 메서드가 호출 스택에 있었다.
2) 예외가 발생한 곳은 제일 윗줄에 있는 method2()
3) main메서드가 method1() 호출, 그리고 method1()은 method2()를 호출했다.
- method2에서 예외가 (강제로) 발생했으나 예외처리를 해주지 않았기 때문에 메서드 종료하고
- 자신을 호출한 method1()에게 예외를 넘겨준다.
- 그러나 main메서드에서조차 예외처리를 해주지 않아서 main이 종료되어
- 프로그램이 예외로 인해 비정상적으로 종료된다.
- 따라서 어느 한 곳에서 반드시 try-catch문으로 예외처리해야한다.
Ex 8-15)
package javaStudy;
import java.io.*;
public class ExceptionEx15 {
public static void main(String[] args) {
// command line에서 입력받은 값을 이름으로 갖는 파일을 생성한다.
File f = createFile(args[0]);
System.out.println(f.getName() + " 파일이 성공적으로 생성되었습니다." );
}
static File createFile(String fileName) {
try {
if( fileName == null || fileName.equals("") )
throw new Exception("파일이름이 유효하지 않습니다.");
}catch (Exception e){
// fileName이 부적절한 경우, 파일이름을 '제목없음.txt'로 한다.
fileName = "제목없음.txt";
}finally {
File f = new File(fileName); // File클래스의 객체를 만든다.
createNewFile(f); // 생성된 객체를 이용해서 파일을 생성한다.
return f;
}
}
static void createNewFile(File f) {
try {
f.createNewFile(); // 파일을 생성한다.
}catch(Exception e) {}
}
}
Note)
- 이 예제는 예외가 발생한 메서드에서 직접 예외를 처리하도록 되어 있다.
- createFile메서드를 호출한 main메서드에서는 예외가 발생한 사실을 알지 못한다.
1.8 finally블럭
- 예외발생 여부와 관계없이 수행되어야 하는 코드
1.9 자동 자원 반환 - try - with - resources 문
- try-catch문의 변형이다.
- 입출력에 사용되는 클래스 중에서는 사용 후에 꼭 닫아줘야하는 것들이 있다.
- 그래야 사용했던 자원이 반환(resource)되기 때문이다.
Ex)
Note) 실행 결과

- main메서드에 두 개의 try-catch문이 있는데 첫 번째 것은 close()에서만 예외를 발생시키고
- 두 번째 것은 exceptionWork()와 close()에서 모두 예외를 발생시킨다.
- 첫번째 것은 일반적인 예외가 발생했을 때와 같은 형태
- 두 번째는 출력형태가 다른.
- 두 예외가 동시에 발생할 수는 없다. 실제 발생한 예외를 'WorkException'이라고한다.
- CloseException은 억제된 예외이다.
-> void addSuppressed(Throwable exception) : 억제된 예외를 추가
-> Throwable [] getSuppressed() : 억제된 예외(배열)을 반환한다.
1.10 사용자 정의 예외 만들기
- 우리가 직접 예외를 정의할 수 있다.
- Exception과 RuntimeException 중에 조상을 선택한다.
Ex)
Note) 실행 결과

- MemoryException, SpaceException 두 개의 사용자 정의 예외 클래스를 새로 만들었다.
- 두 예외는 startInstall()을 수행하는 동안 발생할 수 있으며
- enoughSpace()와 enoughMemory()의 실행 결과에 따라 예외의 종류가 달라지기도한다.
1.11 예외 되던지기(exception re-throwing)
- 예외를 처리한 후에 다시 예외를 발생시키는 것
- 호출한 메서드와 호출된 메서드 양쪽 모두에서 예외처리하는 것
Ex)
Note) 실행 결과

- method1()과 main매서드 양쪽의 catch블럭이 모두 수행되었다.
- method1()의 catch블럭에서 예외를 처리하고도 throw문을 통해 다시 예외발생시켰다
- 그 예외를 main메서드에서 한 번 더 처리했다.
1.12 연결된 예외(chained exception)
- 한 예외가 다른 예외를 발생시킬 수 있다.
- 예외 A가 예외B를 발생시키면 A는 B의 원인예외(cause exception)
- initCause()는 throwable 클래스에 정의 되어 있어서 모든 예외에서 사용 가능.
- 연결된 예외를 사용하는 이유
1) 여러 예외를 하나로 묶어 다루기 위해
2) checked예외를 unchecked예외로 변경하려할 때 (예외처리가 선택적인 사항이 된다.)
3) 예외의 상속 관계를 변경하지 않아도 된다.
Ex)
Note) 실행 결과

- throw new RuntimeException(new MemoryException("메모리가 부족합니다."));
-> MemoryException은 Exception의 자손이므로 반드시 예외처리를 해야한다.
-> 이 예외를 RuntimeException으로 감쌌기 때문에 unchecked예외가 되었다.
'Java > Java의 정석' 카테고리의 다른 글
Chapter 10 날짜와 시간 & 형식화 date, time and formatting (0) | 2022.02.28 |
---|---|
Chapter 09 java.lang 패키지와 유용한 클래스 (0) | 2022.02.24 |
Chapter 07 객체지향 프로그래밍 II (0) | 2022.02.22 |
Chapter 06 객체지향 프로그래밍 I (0) | 2022.02.22 |
Chapter 05 배열(Array) (0) | 2022.02.20 |