프로그램 오류
프로그램이 실행 중 어떤 원인에 의해서 오작동을 하거나 비정상적으로 종료되는 경우
발생시점에 다른 분류
컴파일 에러 컴파일 시에 발생하는 에러
런타임 에러 실행 시에 발생하는 에러
논리적 에러 실행은 되지만, 의도와 다르게 동작하는 것
Java의 런타임 에러
에러(error) 프로그램 코드에 의해서 수습될 수 없는 심각한 오류
예외(exception) 프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류
예외처리는 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것이다.
이를 통해 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지할 수 있다.
예외 클래스의 계층구조
예외처리하기 try - catch문
try {
// 예외가 발생할 가능성이 있는 문장들을 넣는다.
} catch (Exception e1) {
// Exception1이 발생했을 경우, 이를 처리하기 위한 문장을 적는다.
} catch (Exception e2) {
// Exception2가 발생했을 경우, 이를 처리하기 위한 문장을 적는다.
...
} catch (Exception en) {
// ExceptionN이 발생했을 경우, 이를 처리하기 위한 문장을 적는다.
}
try-catch문에서의 흐름
try블록 내에서 예외가 발생한 경우
- 발생한 예외와 일치하는 catch블록이 있는지 확인한다.
- 일치하는 catch블록을 찾게 되면, 그 catch블록 내의 문장들을 수행하고 전체 try-catch문을 빠져나가서 그다음 문장을 계속해서 수행한다. 일치하는 catch블록을 찾지 못하면 예외는 처리되지 못한다.
try블록 내에서 예외가 발생하지 않은 경우
- catch블록을 거치지 않고 전체 try-catch문을 빠져나가서 수행을 계속한다.
예외의 발생과 catch블록
- try블록에서 예외가 발생하면, 발생한 예외를 처리할 catch블록을 찾는다.
- 첫 번째 catch블록부터 순서대로 찾아 내려간다
- 예외의 최고 조상인 Exception을 처리하는 catch블록은 모든 종류의 예외를 처리할 수 있으며 반드시 마지막 catch블록이어야 한다.
printStackTrace()와 getMessage()
printStackTrace() 예외발생 당시의 호출스택에 있었던 메서드의 정보와 예외 메시지를 화면에 출력한다.
getMessage() 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.
멀티 catch블록
JDK1.7부터 여러 catch블록을 '|'을 이용해서 하나의 catch블록으로 합칠 수 있게 되었다.
try {
...
} catch (ExceptionA | ExceptionB e) {
e.printStackTrace();
}
'|'가 연결된 예외 클래스가 조상과 자손의 관계에 있다면 컴파일 에러가 발생한다. 이 경우는 그냥 조상 클래스만 써주는 것과 같기 때문이다.
예외 발생시키기
1. 먼저, 연산자 new를 이용해서 발생시키려는 예외 클래스의 객체를 만든 다음
Exception e = new Exception("고의로 발생시켰음");
2. 키워드 throw를 이용해서 예외를 발생시킨다.
throw e;
메서드에 예외 선언하기
예외를 처리하는 또 다른 방법이다.
void method() throws Exception1, Exception2, ... ExceptionN {
// 메서드의 내용
}
메서드의 선언부에 throws를 사용해 메서드 내에서 발생할 수 있는 예외를 적어준다.
void method() throws Exception {
// 메서드의 내용
}
이렇게 선언하면 모든 종류의 예외가 발생할 가능성이 있다는 의미이다.
메서드의 선언부에 예외를 선언함으로써 메서드를 사용하려는 사람이 어떠한 예외들이 처리되어야 하는지 쉽게 알 수 있는데 모든 종류의 예외가 발생하지 않음에도 Exception을 사용하면 발생할 가능성이 있는 예외의 종류를 예측하기 어렵다.
finally블록
- 예외의 발생여부와 관계없이 실행되어야 하는 코드를 넣는다.
- 선택적으로 사용할 수 있으며, try-catch-finally의 순서로 구성된다.
- 예외가 발생한 경우 try → catch → finally의 순서로 실행된다.
- 예외가 발생하지 않은 경우, try → finally의 순서로 실행된다.
- try 또는 catch블록에서 return문을 만나도 finally블록은 수행된다.
try {
// 예외가 발생할 가능성이 있는 문장들을 넣는다.
} catch (Exception1 e1) {
// 예외처리를 위한 문장을 적는다.
} finally {
// 예외의 발생여부에 관계없이 항상 수행되어야 하는 문장들을 넣는다.
// finally블럭은 try-catch문의 맨 마지막에 위치해야 한다.
}
자동 자원 반환 try-with-resources문
입출력과 관련된 클래스를 사용할 때 유용하다.
입출력에 사용되는 클래스 중에서는 사용한 후 자원 반환을 위해 닫아줘야 하는 것들이 있다.
try {
fis = new FileInpuStream("score.dat");
dis = new DataInputStrea(fis);
...
} catch (IOException ie) {
ie.printStackTrace();
} finally {
try {
if(dis!=null) {
dis.close(); //close()가 예외를 발생시킬 수 있어서 try-catch문을 사용해야한다.
}
} catch (IOException ie) {
ie.printStackTrace();
}
}
이를 try-with-resouces문으로 바꾸면 아래와 같다.
// 괄호()안에 두 문장 이상 넣을 경우 ';'로 구분한다.
try (FileInputStrea fis = new FileInputStrea("score.dat"); DataInputStream dis = new DataInputStream(fis)) {
while(true) {
score = dis.readInt();
SYstem.out.println(score);
sum += score;
}
} catch (EOFException e) {
System.out.println("점수의 총합은 " + sum + "입니다.");
} catch (IOException e) {
ie.printStackTrace();
}
try-with-resource문에 의해 자동으로 객체의 close()가 호출되기 위해서, 클래스가 AutoCloseable이라는 인터페이스를 구현한 것이어야만 한다.
사용자정의 예외 만들기
기존의 예외 클래스를 상속받아서 새로운 예외 클래스를 정의할 수 있다.
class MyException extends Exception {
MyException(String msg) {
super(msg);
}
}
예외 되던지기
- 예외를 처리한 후에 다시 예외를 생성해서 호출한 메서드로 전달하는 것
- 예외가 발생한 메서드와 호출한 메서드, 양쪽에서 예외를 처리해야 하는 경우에 사용한다.
class ExceptionEx17 {
public static void main(String[] args)
{
try {
method1();
} catch (Exception e) {
System.out.println("main메서드에서 예외가 처리되었습니다.");
}
} // main메서드의 끝
static void method1() throws Exception {
try {
throw new Exception();
} catch (Exception e) {
System.out.println("method1메서드에서 예외가 처리되었습니다.");
throw e; // 다시 예외를 발생시킨다.
}
} // method1메서드의 끝
}
연결된 예외
한 예외가 다른 예외를 발생시킬 수 있다. 예외 A가 예외 B를 발생시켰다면, A를 B의 '원인 예외'라고 한다.
try {
startInstall(); // SpaceException 발생
copyFiles();
} catch (SapceException e) {
InstallException ie = new InstallException("설치중 예외발생"); // 예외 생성
ie.initCause(e); // InstallException의 원인 예외를 SpaceException으로 지정
throw ie; // InstallException을 발생시킨다.
} catch (MemoryException me) {
...
}
발생한 예외를 그냥 처리하지 않고 원인 예외로 등록해서 다시 예외를 발생시키는 이유는 여러 가지 예외를 하나의 큰 분류의 예외로 묶어서 다루기 위해서이다.
'JAVA' 카테고리의 다른 글
[java.lang] String 관련 클래스 (0) | 2023.03.09 |
---|---|
[java.lang] Object 클래스 (0) | 2023.03.09 |
[OOP] 내부 클래스(inner class) (0) | 2023.03.08 |
[OOP] 인터페이스(interface) (0) | 2023.03.08 |
[OOP] 추상클래스 (0) | 2023.03.08 |