자바에서 예외 처리 방법
try, catch, finally
try-catch
프로그램 실행 도중 발생된 에러는 어쩔 수 없지만 이외엔 대비처리를 해야한다.
이럴때 이제 대비 처리하는 try-catch문을 작성해줘야한다.
try{
//예외 발생 가능성이 있는 코드
} catch(Exception1 e1){
//Exception1 이를 처리하기 위한 코드
} catch(Exception2 e2) {
//Exception2가 발생시 이를처리하기 위한 코드
}
예시로 문자열을 정수형으로 변환하는 과정중에 발생하는 NumberFormatException 예외를 생각했지만 자바 문서 찾아보니 RuntimeException클래스의 자식이라 try~catch문 예시로 안좋을것같다. 그래서 RuntimeException예외가 아닌 Exception예시중 FileNotFoundException이 발생할 수 있는 파일을 읽어서 가져오는 예시를 준비했다.
예시
public class Main {
public static void main(String[] args) {
BufferedReader reader = null;
reader = new BufferedReader(new FileReader("test.txt"));
String line = reader.readLine();
}
}
오류 발생
FileNotFoundException 오류 문서를 찾아보자
문서 밑에 내용을 더 자세히 보면 아래 과정을 통해 에레메시지가 전달 되는 것을 알 수 있다
그렇다면 이러한 예외로 인해 프로그램 종료가 되지 않을려면 어떡해야할까
바로 catch를 쓰면 된다
public class Main {
public static void main(String[] args) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("text.txt"));
String line = reader.readLine();
} catch (FileNotFoundException e1) {
System.err.println("파일을 찾는 동안 오류가 발생했습니다1: " + e1.getMessage());
} catch (IOException e2){
System.err.println("파일을 읽는 동안 오류가 발생했습니다2: " + e2.getMessage());
}
}
}
결과
getMessage와 printStackTrace()
- get Message(): 발생한 예외 클래스의 인스턴스 저장된 메세지 얻기 가능하다
- printStackeTrace(): 호출스택에 있었던 메서드의 정보와 예외 메세지 출력한다
멀티 catch
자바 7부터 사용가능하다
JDK 1.7부터 여러 catch블럭을 '|'기호를 이용해서 하나의 catch블럭으로 하나로 합칠수 있게 되었다.
중복된 코드를 줄일 수 있다는 장점이 있고 이를 쓸때 하나의 catch블럭에 '|'을 통해 연결하면 된다
예시는 다음과 같다.
try {
//예외 발생 가능성이 있는 코드
} catch (FileNotFoundException |NullPointerException e){
e.getMessage();
}
※주의사항
그 서로간에 관계가 조상과 자손의 관계면 안된다
주의점
- 주의해야할 점은 예외 변수 이름을 다르게 해줘야한다. 왜냐면 같은 참조변수 사용불가이기 때문이다.
- 추가로 try나 catch문은 괄호 생략 불가이다
- 에러 출력문 관련해서 getMessage() 말고 printStackTrace() 메서드 사용법도 있지만
운영할 시스템에 적용시 엄청난 양의 로그가 쌓여서 필요할때만 써야한다 - 추가로 주의점은 아니고 알아두면 좋은게 이제 모든 예외 클래스는 Exception 클래스의 자손이므로
Exception 클래스 타입의 참조변수를 선언해 놓으면 어떤 예외가 발생해도 이 catch 블럭에 의해서
처리 된다
throw
throw 키워드는 예외를 직접 발생시키는데 사용된다. 즉, 예외 객체를 생성하고 해당 예외를
프로그램으로 던진다. 사용이유는 특정 조건이나 상황에서 예외가 발생할때 개발자가 짠 코드가
오류 발생시에도 문제 없이 잘 돌아가는지를 확인하기 위해서 이다. 사용방법은 아래와 같다
public class Main {
public static void main(String[] args) {
BufferedReader reader = null;
try {
//고의적으로 FileNotFoundException 오류 발생
throw new FileNotFoundException("예외 메시지");
} catch (FileNotFoundException e) {
System.err.println("파일을 찾는 동안 오류가 발생했습니다: " + e.getMessage());
}
}
}
throws
해당 메서드가 어떤 예외를 던질 수 있는지를 선언하다. 이것을 통해 컴파일러와
다른 프로그래머에게 메서드에서 발생할 수 있는 예외에 대한 정보를 제공한다.
이를 통해 컴파일러는 해당 메서드를 사용하는 코드에서 예외를 처리하도록 요구한다.
사용법은 다음과 같다
public void readFile() throws IOException {
// 파일을 읽는 코드
}
따라서 개발자는 해당 메서드를 사용할때 예외 처리 코드를 참고하여 짤 수 있다.(throwsException()를
메서드 선언부에 선언해놓으면 try-catch블록 사용안할시 컴파일 에러 발생하기때문에 사실상
예외처리 꼭 쓰라는뜻이다)
finally
finally블럭은 예외의 발생여부에 상관없이 실행되어야할 코드를 포함시킬 목적으로 사용된다.
try-catch문의 끝에 선택적으로 붙여서 사용하며 try-cath-finally순으로 구성된다
try{
// 예외가 발생할 가능성이 있는 문장들을 넣는다
}catch(Exception e){
//예외 처리를 위한 문장을 적는다
}
finally{
//try-catch 마지막에 위치해야함
//finally 블럭은 try-catch문의 맨 마지막에 위치해야한다
}
코드 참고: 자바의 정석
예외 발생시: try -> catch -> finally 순
예외 발생하지 않을시: try -> finally순
try-with-resource
try-with-resource문은 괄호()안에 객체를 생성하는 문장을 넣으면, jdk1.7로부터 추가된 try-catch문으로 사용후 꼭 닫아줘야하는 것들을 처리해준다.
자원이 반환되기 때문인데 이때 자원반환은 메모리반환의 의미가 아니다(메모리 관련된건 가비지 컬렉터에서 처리). 찾아보니 I/O입출력을 사용할때 파일 디스크립터, 파일 또는 다른 I/O리소스를 식별하는데 사용되는 것이다. 좀더 자세히 설명하면 정수 형태의 고유한 식별자로, 커널 내부에서 열린 파일, 소켓, 파이프, 디바이스 및 기타 I/O리소스를 추적고 관리하는데 사용되는것이 있는데 이것의 사용을 멈춤으로써 시스템 리소스를 효율적으로 관리한다.
추가로 try괄호안에 넣으면 try문 나갈때 자동으로 close()해준다
try(FileInputStream fis = new FileInputStream("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 ie){
ie.printStackTrace();
}
코드 참고: 자바의 정석
자바가 제공하는 예외 계층 구조
아래 계층 구조는 자바에서 실행시 발생할 수 있는 오류(Exception &Error)를 클래스로 정의하고 있다.
Throwalbe은 모든 java클래스들이 그렇듯 Object를 암시적으로 상속받고있다. 그래서 아래와 같이 따로 명시되어있지않다.
자바와 Exception은 RuntimeExcxeption과 RuntimeException을 제외한 Exception클래스의 자식클래스 2개로 구분할 수 있는데 이건 밑에서 더 자세히 다루겠다.
RuntimeException과 RE가 아닌것의 차이
위 그림에서 파란색 점선 영역이 CheckedException으로 컴파일러(빌드) 단계에서 검출되고
노란색 영역이 UnCheckedException으로 런타임(JVM구동)시 예외가 발생한다.
RuntimeException
- RuntimeException클래스를 상속받는 자식 클래스들은 주로 치명적인 예외상황을 발생시키지 않는
예외들로 구성되어있다 - try/ catch문을 사용하기보다는 프로그램을 작성하면서 예외가 발생하지 않도록 주의하는 것이 좋다
(ex. null인 문자열 text변수의 길이 호출, text.lenght() 호출하면 NullPointerException발생
따라서 사용자가 프로그램을 잘 작성하자)
ChekcedException
- CheckedException 클래스인 Exception 클래스에 속하는 자식 클래스들은 치명적인 예외상황을
발생 시키기 때문에 반드시 try / catch문을 사용하여 예외처리를 해야한다 - 자바 컴파일러는 RuntimeException 클래스의 자식 클래스에 속하는 예외가 발생할 가능성이 있는
구문에는 반드시 예외를 처리하도록 강제하고 있다. - 위에도 언급했지만 컴파일 단계에서 확인한다
Exception과 Error의 차이
이 2개의 차이를 알아보기전에 먼저 Exception과 Error에 대해 알아보자.
Exception
- 컴퓨터의 에러가 아닌 사용자의 잘못된 조작 또는 개발자의 잘못된 코딩으로 인해 발생하는 프로그램 오류이다.
- 예외 발생시 프로그램 종료된다
- 개발자가 구현한 로직에서 발생한다
- 쓰레드에 영향을 준다(예외 발생시 해당 쓰레드의 실행이 중단될 수도 있다)
Error
- 컴퓨터의 하드웨어의 오동작 또는 고장으로 인해 응용프로그램 이상이 생겼거나 JVM 실행에 문제가 생겼을 경우 바랭하는 것이다
- 프로세스에 영향을 준다
- 시스템 레벨에서 발생한다
차이점
- 예외나 에러는 발생하면 프로그램이 종료가 된다는것은 동일하지만 예외는
사용자의 잘못된 조작또는 코딩으로 인해 발생하기때문에 예외처리를 통해 프로그램을
종료되지 않고 정상적으로 작동되게 만들어 줄 수 있다.
에러는 시스템 환경이나 하드웨어를 수정하거나 개선해야한다
커스텀한 예외 만드는 방법
기존 정의된 예외 클래스 외에 필요에 따라 프로그래머가 새로운 예외 클래스를
정의하여 사용할 수 있다. Exception 클래스를 상속받거나, 필요에 따라 알맞은
예외 클래스를 상속받아 만든다.
public class MyException {
public static void main(String[] args) throws SpaceException {
methodA(5);
}
static void methodA(int space) throws SpaceException {
if (space < 1) {
throw new SpaceException("공간 부족");
}
}
}
class SpaceException extends Exception {
public SpaceException(String message) {
super(message); //조상 클래스인 Exception의 생성자 호출
}
}
예외 되던지기
한 메서드에서 발생할 수 있는 예외가 여러 개인 경우, 일부는 메서드 내부에서
처리하고 일부는 선언부에 지정해서 메서드를 호출한 쪽에서 처리할 수 있다.
또, 하나의 예외에 대해서도 양쪽에서 처리하도록 할 수 있는데 이를 '예외 되던지기'라고한다.
사용 상황은 다음과 같다
- 예외를 발생시킨 메서드에서 예외를 처리할 필요가 없고, 상위 호출자에게 예외 처리를 위임하고자 할때 사용
- 예외를 발생시킨 위치에서 예외에 대한 정보를 보존하면서 다른 메서드로 예외를 전달하고자 할때 사용
참고
자바의 정석(저자 남궁성)
-Exception 전반적인 내용
https://wisdom-and-record.tistory.com/46
-예외 계층과 RunitimeException, RE의 차이점
'자바(Java)' 카테고리의 다른 글
[자바] 자바 Enum (0) | 2023.09.27 |
---|---|
[자바] 자바 멀티쓰레드 프로그래밍 (0) | 2023.09.21 |
[자바] 자바 인터페이스 (0) | 2023.09.08 |
[자바] 자바 패키지(package) (0) | 2023.08.28 |
[자바]자바 상속, 다이나믹&더블 메소드 디스패치 (0) | 2023.08.21 |