[작성일: 2023. 01. 31]
목차
프로그램 오류
- 컴파일 에러(compile-time error): 컴파일할 때 발생하는 에러
- 런타임 에러(runtime error): 실행할 때 발생하는 에러(실행은 되지만 프로그램이 종료됨)
- 논리적 에러(logical error): 작성 의도와 다르게 동작(프로그램 종료되지 않음)
✏️ Java의 런타임 에러
에러는 어쩔 수 없지만 예외는 처리해야 함.
에러(error) 프로그램 코드에 의해서 수습될 수 없는 심각한 오류 (메모리 부족 등)
예외(exception) 프로그램 코드에 의해 수습될 수 있는 다소 미약한 오류
처리 불가능한 에러 OOM(Out Of Memory)
✏️ 예외처리의
정의 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드 작성
목적 프로그램의 비정상 종료를 막고 정상적인 실행상태를 유지하는 것
Exception클래스들(+자손) 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외(체크드 예외-필수)
RuntimeException클래스들(+자손) 프로그래머의 실수로 발생하는 예외(언체크드 예외-선택)
예외 처리(try-catch문)
- 예외가 발생하면 이를 처리할 catch블럭을 찾아서 내려감.
- 일치하는 catch블럭이 없으면 예외 처리 안 됨
- Exception이 선언된 catch블럭은 모든 예외 처리를 함.(마지막에 와야 함)
✏️ try 블럭 내에서 예외가 발생한 경우,
1. 발생한 예외와 일치하는 catch블럭이 있는지 확인하기
2. 일치하는 catch블럭을 찾게 되면, 그 catch블럭 내의 문장들을 수행하고 전체 try-catch문을 빠져나가서 그 다음 문장을 계속해서 수행함.
3. 만일 일치하는 catch블럭을 찾지 못하면 예외 처리 되지 못 함.
✏️ try블럭 내에서 예외가 발생하지 않은 경우,
1. catch블럭을 거치지 않고 전체 try-catch문을 빠져나가서 수행을 계속 함.
try {
// 예외가 발생할 가능성이 있는 문장
} catch (Exception1 e1) {
// Exception1이 발생했을 경우, 이를 처리하기 위한 문장
} catch (Exception2 e2) {
// Exception2이 발생했을 경우, 이를 처리하기 위한 문장
} catch (ExceptionN eN) {
// ExceptionN이 발생했을 경우, 이를 처리하기 위한 문장
} finally
// 무조건 실행할 문장이 없으면 finally 안 써도 됨.
// 예외가 발생하든 안 하든 "무조건" 실행 할 문장들
}
// if문과 달리 괄호 생략 불가
printStackTrace()와 getMessage()
e.getMessage() 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있음.
e.toString() 오류의 조금 더 자세한 내용을 String으로 얻을 수 있음.
e.printStackTrace() 예외 발생 당시의 호출스택에 있던 메서드의 정보와 예외 메시지를 화면에 출력함.
public static void main(Stirng[] args) {
System.out.println(1);
System.out.println(2);
try {
...
System.out.println(0/0); // 예외 발생
...
} catch (ArithmeticException ae) {
ae.printStackTrace();
// 참조변수 ae를 통해 생성된 ArithmeticException 인스턴스에 접근 가능
System.out.println("예외 메시지: " + ae.getMessage());
} // try-catch의 끝
System.out.println(6);
} // main메서드 끝
}
// 결과
1
2
3
java.lang.ArithmeticException: / by zero
...
예외 메시지 : / by zero
6
멀티 catch블럭
- 내용이 같은 catch블럭을 하나로 합친 것(JDK 1.7부터)
- 멀티 catch 안의 클래스가 부모-자식 관계면 안 됨.(부모 타입의 클래스만 적어주면 됨.)
- 참조변수로 사용할 수 있는 건 공통된 부분만 사용 가능. 특정 메서드를 호출하면 에러 발생.
try {
...
} catch ( ExceptionA | ExceptionB e) {
e.printStackTrace();
}
예외 발생시키기
1. 연산자 new를 이용해서 발생시키려는 예외 클래스의 객체 만들기
Exception e = new Exception("고의로 발생시켰음.");
2. 키워드 throw를 이용해서 예외 발생시키기
throw e;
public static void main(String[] args) {
try {
exception e = new Exception("고의로 발생시켰음."); // e.getMessage()출력
throw e; // 예외 발생시키기
// throw new exception("고의로 발생시켰음.") // 위의 두 줄 한 줄로 줄이기
} catch (Exception e) {
System.out.println("에러 메시지: " + e.getMessage());
e.printStackTrace();
}
System.out.println("프로그램이 정상 종료되었습니다.");
}
checked예외와 unchecked예외
✏️ checked예외 컴파일러가 예외 처리 여부를 체크
예외 처리 필수: Exception과 자손
IOException, ClassNotFoundException, ...
try-catch블럭을 필수로 사용함.
✏️ unchecked예외 컴파일러가 예외 처리 여부를 체크 안 함.
예외 처리 선택: RuntimeException과 자손
ArithmeticException, ClassCastException, NullPointerException, indexOutOfBoundsException, ...
try-catch 블럭을 선택적으로 사용함.
예외 선언하기
- 예외 처리하는 방법: try-catch문(예외 직접 처리하기), 예외 선언하기(예외 떠넘기기), 은폐(감추기)
- 메서드가 호출 시 발생가능한 예외를 호출하는 쪽에 알리는 것
- 예외를 발생시키는 키워드 throw와 예외 메서드에 선언할 때 쓰이는 throws를 잘 구별할 것.
- finally블럭: 예외 발생여부와 관계없이 수행되어야 하는 코드를 넣음.(try-catch문의 맨 마지막에 위치)
import java.io.*;
class Ex8_10 {
public static void main(String[] args) {
try {
File f = createFile(args[0]); // Arguments탭에 값 지정해주기
System.out.println(f.getName() + "파일이 성공적으로 생성되었습니다.");
} catch (Exception e) {
System.out.println(e.getMessage()+" 다시 입력해 주시기 바랍니다.");
} finally {
// 예외 발생여부에 관계없이 항상 수행되어야 하는 문장
// try-catch문의 맨 마지막에 위치해야 함.
}
} // mailn메서드의 끝
static File createFile(String fileName) throws Exception {
if(fileName == null || fileName.equals(""))
throw new Exception("파일 이름이 유효하지 않습니다.)";
File f = new File(fileName); // File클래스 객체 만들기
// File 객체의 createNewFile메서드를 이용해 실제 파일 생성하기.
f.createNewFile();
return f; // 생성된 객체의 참조 반환.
} // createFile메서드 끝
} // 클래스의 끝
사용자 정의 예외 만들기
- 사용자가 직접 예외 클래스를 정의할 수 있음.
- 조상은 Exception과 RuntimeException중에서 선택
class MyException extends Exception { // 조상 선택 가능
MyException(String msg) { // 문자열을 매개변수로 받는 생성자
super(msg); // 조상인 Exception클래스의 생성자 호출
}
}
예외 되던지기(Exception re-throwing)
- 예외를 처리한 후에 다시 예외를 발생시키는 것
- 호출한 메서드와 호출된 메서드 양 쪽 모두에서 예외처리를 하는 것
- 사용 가능한 특별한 케이스는 없지만 발생할 수 있는 경우가 있기는 함.
class Ex8_12 {
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 메서드에서 예외가 처리되었습니다.");
thorw e; // 다시 예외 발생시켜서 호출시킨 곳으로 던지기
}
} // method1 메서드의 끝
}
// 결과
method1 메서드에서 예외가 처리되었습니다.
main 메서드에서 예외가 처리되었습니다.
연결된 예외(Chained Exception)
- 한 예외가 다른 예외를 발생시킬 수 있음.
- 예외 안에 또 다른 예외를 포함시키는 것
- 예외 A가 B를 발생시키면 A는 B의 원인 예외(cause exception)
- Throwable은 예외(Exception)와 Error의 조상
✏️ 이유 1
여러 예외를 하나로 묶어서 다루기 위해
try { intstall(); } catch(InstallException e) { e.printStackTrace(); } catch(Exception e) { e.printStackTrace(); }
✏️ 이유 2
checked예외를 unchecked예외로 변경하기 위해static void startInstall() throws SpaceException { if(!enoughSpace()) throw new SpaceException("설치할 공간이 부족합니다."); if(!enoughMemory()) throw new RuntimeException(new MemoryException("메모리가 부족합니다.")); } // startInstall메서드의 끝
Throwable initCause(Throwable cause) // 지정한 예외를 원인 예외로 등록, 예외A
Throwable getCause() // 원인 예외를 반환
public class Throwable implements Serializable {
...
private Throwable cause = this; // 객체 자신(this)을 원인 예외로 등록
...
private synchronized Throwable initCause(Throwable cause) {
...
this.cause = cause; // cause를 원인 예외로 등록
return.this;
}
...
}
🐣 해당 게시글은 자바의 정석(남궁성 님) 영상으로 함께 공부하며 요약/정리한 글입니다.
🐣 입문 개발자가 작성한 글이므로 틀린 내용이나 오타가 있을 수 있습니다.