오늘 원래 예외처리 관련해서 배우기로 해서 열심히 예습했는데, 강사님의 사정으로 인해 내일로 미루어졌다! 아쉽..
강사님께서 항상 깊게 파고들면서 강의를 진행하시는데 배경지식이 부족하면 따라가기가 조금 벅차서 예습을 꾸준히 해보려고 노력중이다.
그래도 하루 더 공부할 시간이 생겨서 내심 안심하면서 오늘 예습했던 예외처리를 정리해보려고 한다.
예외 처리란 프로그램이 실행 중에 예상치 못한 상황이 발생할 때, 이를 처리하는 방법을 말한다.
예외 처리를 제대로 다루지 않으면 프로그램의 안정성이 저하되고, 예외 상황이 발생할 경우 프로그램이 강제 종료될 수 있다.
따라서 오류가 발생한 경우에는 log를 남겨 오류를 수정하는 것이 중요하다.
컴파일 오류(Compile Error) : 코드를 컴파일하는 과정에서 발생하는 에러로 오타나 잘못된 자료형 체크 등의 경우에 발생한다. 컴파일 오류가 발생하면 해당 코드는 컴파일 단계에서 컴파일러에 의해 처리되지 않고 오류 메시지가 출력되며, 컴파일이 완료되지 않는다. 하지만 소스 코드의 문법 오류를 수정하여 해결할 수 있다.
실행 오류(Runtime Error) : 프로그램이 실행되는 동안 발생하는 에러로 컴파일 단계에서는 발견되지 않았지만 프로그램이 실행되는 과정에서 발생하는 오류이다. 프로그램이 비정상적으로 종료가 되는 경우에는 심각한 장애를 발생할 수도 있다.
오류의 종류
-시스템 오류(error) : 메모리 부족(OutOfMemoryError)이나 스택오버플로우(StackOverflowError)와 같이 일단 발생하면 프로그래머가 처리할 수 없는 오류이다.
-예외(exception) : 발생하더라도 프로그램에서 수습이 가능한 오류이다.
이제 예외처리를 하는 방법을 알아보자! 자바에서의 예외 처리는 try-catch 블록을 사용하여 예외를 처리하는 방식이 일반적이라고 할 수 있다.
try 블록 내에 예외가 발생할 수 있는 코드를 작성하고, catch 블록에서 예외를 처리하는 로직을 작성한다. 예외가 발생하지 않으면 catch 블록은 실행되지 않는다.
10을 0으로 나누는 코드를 통해서 예시를 들자면,
public class DivisionExample {
public static void main(String[] args) {
int dividend = 10;
int divisor = 0;
int result = dividend / divisor;
System.out.println("결과: " + result);
}
}
10을 0으로 나누려고 하기 때문에, ArithmeticException이 발생하게 된다. 발생하는 오류의 종류는 컴파일을 실행했을 때의 안내문구를 보면 정확하게 알 수 있다!
public class DivisionExample {
public static void main(String[] args) {
int dividend = 10;
int divisor = 0;
try {
int result = dividend / divisor;
System.out.println("결과: " + result);
} catch (ArithmeticException e) {
System.err.println("0으로 나눌 수 없습니다.");
}
}
}
이렇게 try-catch 문을 통해서 프로그램이 비정상으로 종료되는 것이 아니라 예외 처리로 넘어가서 정상적으로 컴파일 되는 것을 볼수있다.
try-catch 문에서 finally 블록이 추가된 구문이다. finally 블록은 예외 발생 여부와 상관없이 항상 실행되는 부분으로, 예외 발생 시에도, 예외가 발생하지 않은 경우에도 항상 실행되는 코드를 작성해준다. try 블록 안에서 예외가 발생하면, 해당 예외에 맞는 catch 블록이 실행되고, 예외가 발생하지 않으면 catch 블록은 건너뛰고 finally 블록이 실행된다.
파일을 읽는 코드를 통해서 예시를 들자면,
public class FileExample {
public static void main(String[] args) {
FileInputStream fileInputStream = null;
try {
// 파일을 읽는 작업 수행
fileInputStream = new FileInputStream("file.txt");
// 파일에서 데이터를 읽는 로직
System.out.println("파일 읽기 완료");
} catch (FileNotFoundException e) {
// 파일이 없는 경우 예외 처리
System.err.println("파일을 찾을 수 없습니다.");
} catch (IOException e) {
// 입출력 예외 처리
System.err.println("입출력 오류가 발생하였습니다.");
} finally {
// 예외 발생 여부와 상관없이 항상 실행되는 로직
try {
if (fileInputStream != null) {
fileInputStream.close();
}
} catch (IOException e) {
System.err.println("파일을 닫는 중 오류가 발생하였습니다.");
}
}
}
}
try-with-resources는 자동으로 닫아주는 구문이다. 예를 들어 파일이나 네트워크 연결 등을 사용할 때, try-with-resources 구문을 사용하면 명시적으로 닫지 않아도 자동으로 닫히게 되어, 안전하게 관리할 수 있다.
이것도 파일을 읽는 코드를 통해서 예시를 들자면,
public class FileExample {
public static void main(String[] args) {
try (FileInputStream fileInputStream = new FileInputStream("file.txt")) {
// 파일을 읽는 작업 수행
// 파일에서 데이터를 읽는 로직
System.out.println("파일 읽기 완료");
} catch (FileNotFoundException e) {
// 파일이 없는 경우 예외 처리
System.err.println("파일을 찾을 수 없습니다.");
} catch (IOException e) {
// 입출력 예외 처리
System.err.println("입출력 오류가 발생하였습니다.");
}
}
}
try 블록을 벗어나면 자동으로 FileInputStream 객체가 close() 메서드를 호출하여서 close() 메서드를 직접 호출하지 않아도 관리할 수 있다.