Java의 예외처리
예외 처리의 궁극적인 목적은 런타임 오류를 처리하고 이를 복구하고 애플리케이션의 정상적인 흐름을 유지하기 위한 메커니즘을 제공하는 것입니다
즉 오류를 복구하고 프로그램을 완전히 중단시키는 대신 프로그램 실행을 계속하는 메커니즘을 제공하는 것입니다.
또한, 실행 오류가 발생한 경우 오류의 과정을 재현하는 것은 현실적으로 힘들기 때문에 에러 발생시 log를 남겨서 추후 log 분석을 통해 그 원인을 파악하여 bug를 수정하는 것이 중요합니다
오류의 종류 : 컴파일 오류 VS 실행 오류
컴파일 오류(compile error)
- 프로그램 코드 작성 중 발생하는 문법적 오류
- 최근에는 IDE에서 대부분의 컴파일 오류는 detection 됨
실행 오류(runtime error)
- 실행 중인 프로그램이 의도 하지 않은 동작(bug)을 하거나 프로그램이 중지 되는 오류
- 실행 오류는 비정상 종료가 되는 경우 시스템의 심각한 장애를 발생할 수 있음
Java의 오류 및 예외 처리
자바는 안전성이 중요한 언어로 대부분 프로그램에서 발생하는 오류에 대해 문법적으로 예외 처리를 해야합니다
Throwable 클래스는 하위 클래스 Error 및 Exception을 포함하여 Java 언어의 모든 오류 및 예외의 상위 클래스입니다.
Error 클래스
시스템 오류를 의미합니다. 가상 머신에서 발생하고, 프로그래머가 처리할 수 없는 오류를 담당합니다
- 동적 메모리가 없는 경우
- 스택 메모리 오버 플로우
Exception 클래스
모든 예외 클래스의 최상위 클래스로써 프로그램에서 제어 할 수 있는 오류를 담당합니다.
- 읽어들이려는 파일이 존재하지 않는 경우
- 네트워크나 DB 연결이 안되는 경우
예외 처리하는 방법
Try-catch 문
try 블록에서는 예외가 발생할 수 있는 코드를 작성하고, try 블록에서 예외가 발생하면 catch 블록이 실행됩니다
try{
예외가 발생 할 수 있느느 코드 부분
}catch(처리할 예외 타입 e){
try 블록 안에서 예외가 발생했을 때 예외 처리를 할 부분
}
프로그래머가 예외를 처리해야 하는 경우의 예는 배열 오류를 처리하는 경우입니다.
public class ArrayExceptionHandling {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
try{
for(int i=0; i<=5; i++){
System.out.println(arr[i]);
}
}catch(ArrayIndexOutOfBoundsException e){
System.out.println(e);
}
System.out.println("The program did not terminate abnormally.");
}
}
Try-catch-finally 문
finally 블록은 파일 닫기 또는 네트워크 연결과 같은 리소스 해제와 같은 무조건 실행 되야 하는 흐름을 구현합니다.
try{} 블록이 실행되면 finally{} 블록이 항상 실행됩니다.
return 문이 있더라도 finally 블록은 계속 호출됩니다.
컴파일러에서 처리 중인 파일 오류의 예입니다.
public class FileExceptionHandling {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("a.txt");
} catch (FileNotFoundException e) {
System.out.println(e);
//return;
}finally{
if(fis != null){
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("This always runs.");
}
System.out.println("This runs too.");
}
}
Try-with-resources 문 - 리소스 처리를 위한 지저분한 코드 해결
finally에서 주로 리소스 해제 등을 하게 되는데 이는 앞선 코드에서 알 수 있다시피 지저분한 코드를 필연적으로 만들게 됩니다
Java 7에서부터는 그래서 close()가 호출되지 않아도 사용된 리소스를 자동으로 해제합니다.
- Java 9부터 리소스는 try() 외부에서 선언할 수 있으며 변수만 try(obj) 형식으로 사용할 수 있습니다.
try{} 블록은 코드가 정상적으로 실행되든 예외가 발생하든 블록에서 열린 리소스를 자동으로 해제합니다.
이 때 리소스 클래스는 AutoCloseable 인터페이스를 구현해야 합니다. 해당 인터페이스가 생성되면 항상 close 메소드가 실행됩니다.
FileInputStream은 AutoCloseable을 구현합니다.
public class AutoCloseObj implements AutoCloseable{
@Override
public void close() throws Exception {
System.out.println("The resource has been closed");
}
}
public class AutoCloseTest {
public static void main(String[] args) {
AutoCloseObj obj = new AutoCloseObj();
try (obj){
throw new Exception();//force exception
}catch(Exception e) {
System.out.println("This is the exception part.");
}
}
}
예외처리 지연 방법 : Throws
try-catch 블록을 사용하여 예외가 발생하는 곳에서 직접 처리하거나 throws
키워드를 사용하여 호출 메서드로 처리를 연기하는 것입니다.
throws
키워드는 Java의 클래스와 메서드 모두에서 사용할 수 있습니다.
throws
키워드를 사용하면 메서드가 throw할 수 있는 예외 유형을 선언할 수 있습니다.
이는 예외가 메서드 내에서 처리되지 않으며 호출 메서드 또는 상위 수준 메서드에 의해 처리되어야 함을 나타냅니다.
호출 메서드는 try-catch 블록으로 이러한 예외를 처리하거나 자체 throws
절을 사용하여 예외를 다시 던질 수 있습니다.
Throws VS Try-catch
“throws” 키워드는 메서드 서명에서 메서드가 하나 이상의 확인된 예외를 throw할 수 있음을 나타내는 데 사용됩니다.
이러한 예외는 try-catch 블록을 사용하여 코드를 호출하여 포착하고 처리하거나 추가 “throws” 선언을 통해 호출 스택 위로 전파할 수 있습니다.
반면에 “try-catch” 블록은 코드 블록 실행 중에 발생하는 예외를 포착하는 데 사용됩니다.
“try” 블록은 예외를 던질 수 있는 코드를 포함하고 “catch” 블록은 예외를 처리할 코드를 포함합니다.
“try” 블록에서 예외가 발생하면 해당 “catch” 블록의 코드가 실행됩니다.
요약하면 "throws"는 메소드에 의해 발생할 수 있는 잠재적 예외를 선언하는 데 사용되는 반면 "try-catch"는 코드 블록 실행 중에 발생하는 실제 예외를 처리하는 데 사용됩니다.
예시 코드
다음 코드에서 loadClass
메서드는 FileNotFoundException
및 ClassNotFoundException
이라는 두 개의 확인된 예외를 throw합니다.
이 예외는 메서드 내에서 처리되지 않지만 throws
키워드를 사용하여 선언됩니다. 호출 메서드인 main
은 try-catch 블록으로 이러한 예외를 처리합니다.
public class ThrowsException {
public Class loadClass(String fileName, String className) throws FileNotFoundException, ClassNotFoundException {
FileInputStream fis = new FileInputStream(fileName);
Class c = Class.forName(className);
return c;
}
public static void main(String[] args) {
ThrowsException test = new ThrowsException();
try {
test.loadClass("a.txt", "java.lang.String");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
메서드가 여러 예외를 throw하는 경우 아래와 같이 파이프 |
기호를 사용하여 예외를 함께 잡을 수 있습니다.
try {
test.loadClass("a.txt", "java.lang.String");
} catch (FileNotFoundException | ClassNotFoundException e) {
e.printStackTrace();
}
마지막으로 Exception
클래스는 선행 catch 블록에서 포착되지 않은 모든 예외 유형을 포착할 수 있는 범용 핸들러로 사용됩니다. Exception
블록은 특정 예외 블록 뒤에 와야 하며, 그렇지 않으면 특정 블록에서 포착해야 하는 예외를 포함하여 모든 예외를 포착합니다.
try {
test.loadClass("a.txt", "java.lang.String");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
부족한 점이나 잘못 된 점을 알려주시면 시정하겠습니다 :>
'DEV > Java' 카테고리의 다른 글
Java의 입출력 스트림 - 🐥 카카오 테크 캠퍼스 (0) | 2023.05.03 |
---|---|
Java의 로그 남기기 - 🐥 카카오 테크 캠퍼스 (0) | 2023.05.03 |
Java의 Reduce - 🐥 카카오 테크 캠퍼스 (0) | 2023.05.02 |
Stream (0) | 2023.05.02 |
Java의 Lambda - 🐥 카카오 테크 캠퍼스 (0) | 2023.05.02 |