에러(Error)는 일단 발생하면 복구할수 없는 심각한 오류
예외(Exception)는 발생하더라도 수습이 가능한 비교적 덜 심각한 오류
https://simplesnippets.tech/exception-handling-in-java-part-1/
try {
// 예외가 발생할 가능성이 있는 코드를 삽입
}
catch (ExceptionType1 e1) {
// ExceptionType1 유형의 예외 발생 시 실행할 코드
}
catch (ExceptionType2 e2) {
// ExceptionType2 유형의 예외 발생 시 실행할 코드
}
finally {
// finally 블럭은 옵셔널
// 예외 발생 여부와 상관없이 항상 실행
}
void method() throws Exception1, Exception2, ... ExceptionN {
// 메서드 내용
}
// ----------------------------------------------------
public static void main(String[] args) {
try {
someClass.method();
} catch (Exception1 e) {
System.out.println(e.getMessage());
}
}
try{
throw new MyException("예외 발생 !!!!!!");
} catch (Exception e) {
System.out.println( e.getMessage() );
System.out.println( e.toString() );
e.printStackTrace();
}
e.getMessage()
예외 발생 !!!!!!
e.toString()
ExceptionTest.ExceptionTest$MyException: 예외 발생 !!!!!!
e.printStackTrace()
ExceptionTest.ExceptionTest$MyException: 예외 발생 !!!!!! at ExceptionTest.ExceptionTest.main(ExceptionTest.java:24)
Exception e = new Exception("고의로 발생시키는 예외");
throw e; // 예외 발생
-------------------------------------------------------
throw new Exception("고의로 발생시키는 예외"); // 예외 발생
throw 예외인스턴스
를 통해 의도적으로 예외를 발생 시킬 수 있다.class MyException extends RuntimeException {
private final int ERROR_CODE;
// 생성자를 통한 초기화
MyException(String msg, int errCode) {
super(msg);
ERROR_CODE = errCode;
}
MyException(String msg) {
this(msg, 100);
}
public int getERROR_CODE() {
return ERROR_CODE;
}
}
보통은 Exception 클래스 또는 RuntimeException 클래스로부터 상속받아 만든다.
필요에 따라서 알맞은 예외 클래스 역시 선택 가능
가능하면 새로운 예외 클래스를 만들기보다 기존의 예외 클래스를 활용하자
예외가 발생할 메서드에서 try-catch 문을 통해 예외처리를 해줌과 동시에
메서드 선언부에 throws 를 통해 발생할 예외를 지정해주어야한다.
public static class ThrowExceptionTest{
public void reThrowing() throws MyException{
try {
throw new MyException("첫번째 예외");
} catch (MyException e) {
System.out.println("첫번째 catch : e.getMessage() : " + e.getMessage());
throw new MyException("두번째 예외"); // 예외 처리 후 다시 예외 발생
}
}
}
public static void main(String[] args) {
ThrowExceptionTest throwExceptionTest = new ThrowExceptionTest();
try {
throwExceptionTest.reThrowing(); // 예외 가능성 메서드 호출
} catch (MyException e) {
System.out.println("두번째 catch : e.getMessage() : " + e.getMessage());
}
}
하나의 예외가 다른 예외를 발생시킬수 있는 상황에서 사용
initCause() 를 통한 예외의 원인인 예외를 등록
사용하는 경우
// 설치 실패 예외
static class InstallException extends RuntimeException {
private final int ERROR_CODE;
// 생성자를 통한 초기화
InstallException(String msg, int errCode) {
super(msg);
ERROR_CODE = errCode;
}
InstallException(String msg) {
this(msg, 100);
}
public int getERROR_CODE() {
return ERROR_CODE;
}
}
// 설치 공간 부족 예외
static class NotEnoughSpaceException extends RuntimeException {
private final int ERROR_CODE;
// 생성자를 통한 초기화
NotEnoughSpaceException(String msg, int errCode) {
super(msg);
ERROR_CODE = errCode;
}
NotEnoughSpaceException(String msg) {
this(msg, 200);
}
public int getERROR_CODE() {
return ERROR_CODE;
}
}
// 설치작업 수행 메모리 부족 예외
static class NotEnoughMemoryException extends RuntimeException {
private final int ERROR_CODE;
// 생성자를 통한 초기화
NotEnoughMemoryException(String msg, int errCode) {
super(msg);
ERROR_CODE = errCode;
}
NotEnoughMemoryException(String msg) {
this(msg, 300);
}
public int getERROR_CODE() {
return ERROR_CODE;
}
}
public static class ChainedExceptionTest{
// 남은 설치 공간 확인
private boolean checkRemainSpace(){
return false;
}
// 남은 설치작업을 수행할 메모리 확인
private boolean checkRemainMemory(){
return false;
}
// 설치 시작
private void startInstall() throws NotEnoughSpaceException, NotEnoughMemoryException{
if (!checkRemainSpace()){
throw new NotEnoughSpaceException("설치 공간 부족 !!!!");
}
if (!checkRemainMemory()){
throw new NotEnoughMemoryException("설치작업을 수행할 메모리 부족 !!!!");
}
}
// 파일 복사
private void copyFiles(){};
// 임시파일 삭제
private void deleteTempFiles(){};
// 설치과정 수행
public void install() throws InstallException{
try {
startInstall(); // 예외 발생
copyFiles();
} catch (NotEnoughSpaceException se){
InstallException ie = new InstallException("설치중 예외 발생");
ie.initCause(se);
throw ie;
} catch (NotEnoughMemoryException me){
InstallException ie = new InstallException("설치중 예외 발생");
ie.initCause(me);
throw ie;
} finally {
deleteTempFiles();
}
}
}
public static void main(String[] args) {
// 테스트
ChainedExceptionTest chainTest = new ChainedExceptionTest();
try{
chainTest.install();
} catch (InstallException ie) {
ie.printStackTrace();
}
}
// 설치과정 수행
public void install() throws InstallException{
try {
startInstall(); // 예외 발생
copyFiles();
} catch (NotEnoughSpaceException se){
InstallException ie = new InstallException("설치중 예외 발생");
ie.initCause(se);
throw ie;
} catch (NotEnoughMemoryException me){
InstallException ie = new InstallException("설치중 예외 발생");
ie.initCause(me);
throw ie;
} finally {
deleteTempFiles();
}
}
Throwable initCause(Throwable cause)
Throwable getCause()
- 원인 예외를 반환한다.
사용한 후 반드시 사용한 자원을 반환해주어야하는 클래스들이 있다.
주로 입출력(I/O) 관련 클래스들을 다룰때 유용하게 사용할 수 있다.
기존의 try-catch-finally 구문에서는 finally 블럭 안에 자원을 반환하는 코드를 두어
작업중 예외가 발생하더라도 자원이 반환되도록 구성하였다.
이경우 finally 안에서 예외가 발생하면 ?
DataInputStream 이 상속받고있는 상위클래스 FilterInputStream 의 close()
IOException 이 발생할 수 있다.
이를 위해 finally 블럭 안에서도 예외처리를 해주어야한다.
FileInputStream fis;
DataInputStream dis;
try {
fis = new FileInputStream("dataFile.dat");
dis = new DataInputStream(fis);
// 이하 생략
} catch (IOException ie ){
ie.printStackTrace();
} finally {
try {
if (dis != null){
dis.close();
}
} catch (IOException ie){
ie.printStackTrace();
}
}
int score = 0;
int sum = 0;
// 괄호 안에 두문장 이상을 넣을 경우 세미콜론으로 구분
try(FileInputStream fis = new FileInputStream("score.dat");
DataInputStream dis = new DataInputStream(fis)) {
// try 블럭 내 구문 수행
while (true){
score = dis.readInt();
System.out.println(score);
sum += score;
}
} catch (EOFException eof ){
System.out.println("총 점수 합 : " + sum);
} catch (IOException ie) {
System.out.println("catch IOException");
ie.printStackTrace();
} finally {
System.out.println("finally");
}
try-with-resources 문의 괄호안에 객체를 생성하는 코드를 넣으면, 해당 객체는 따로 close()를 호출하지 않아도 try 블럭을 벗어나는 순간 자동으로 close() 가 호출된다.
자동으로 cloase() 가 호출되기 위해선 닫아야하는 클래스가
AutoCloseable 인터페이스를 구현한것이어야한다.
적용
static class CloseableResource implements AutoCloseable {
public void executeFirstException(boolean exception) throws FirstException{
System.out.println("executeException() 호출 !! 예외 throw 여부 : " + exception);
if (exception){
throw new FirstException("executeException() 에서 발생");
}
}
public void close() throws CloseException {
System.out.println("close() 호출 !!! 무조건 CloseException 발생 ");
throw new CloseException("close() 에서 발생");
}
}
// 첫번째 예외
static class FirstException extends Exception {
FirstException(String msg) {
super(msg);
}
}
// close() 호출시 발생하는 예외
static class CloseException extends Exception {
CloseException(String msg) {
super(msg);
}
}
public static void main(String[] args) {
try (CloseableResource cr = new CloseableResource()) {
// 매개변수 boolean 값에 따라 예외 throw 여부 결정
cr.executeFirstException(true);
} catch (FirstException fe) {
fe.printStackTrace();
} catch (CloseException ce) {
ce.printStackTrace();
}
System.out.println();
System.out.println("-".repeat(50));
System.out.println();
}
첫번째 매서드executeFirstException()를 호출하고 매개변수 boolean 값에 따라 내부에서 예외를 호출한다.
예외 발생 여부를 떠나 두 경우 모두 close() 를 자동으로 호출한다.
close() 는 내부에서 다른 예외를 발생시킨다.
executeFirstException(false) 지정 시
executeFirstException(true) 지정 시
Suppressed:
머릿말 이후에 해당 정보가 출력된다.void addSuppressed(Throwable exception)
: 억제된 예외를 추가Throwable[] getSuppressed() :
억제된 예외를 반환참고