본문 바로가기
Learning-log/JAVA

JAVA - 예외 ( 2022.09.02~2022.09.03)

by why제곱 2022. 9. 3.

본 게시글은 유튜브 인강을 통해 하루 동안 공부한 내용을 바탕으로 복습한 내용입니다.

내용에 오류가 있거나 보충할 내용이 있다면 댓글 남겨주시면 참고하도록 하겠습니다.

 

유튜브 인강은 생활코딩의 Java 입문수업(생활코딩) 을 참고하였습니다.

자바 수업을 리뉴얼 했습니다 - YouTube

 

 


1. 예외란? 

프로그램 작동시 각종 이유로 인해 오류가 발생하는 것을 말한다. 이를 해결하는 것을 예외처리라고 하며, 오류없는 애플리케이션을 만들기 위해서 예외처리는 꼭 필요한 기능이다.

 

2. 예외 발생 예시

 

 

1) 0으로 나누는 경우 : ArithmeticException

 

2) 배열에서 존재하지 않는 인덱스의 값을 호출하는 경우 : ArrayIndexOutOfBoundsException

 

3) 읽어야 할 파일이 존재하지 않을 경우 :  FileNotFoundException

 

 

 

 

 

3. 예외 처리 방법 및 예외 정보 출력

 

1) try - catch 

 

예외가 발생할 가능성이 있는 코드를 실행 후, 예외가 발생하면 catch 구문 실행. 

 

try {
	예외 발생 가능성이 있는 코드;
} catch (예외클래스 인스턴스 : 매개변수 설정 ) { 
	예외가 발생했을 때 실행되는 코드;
}

 

- 예외 종류에 따라 실행되는 코드를 달리하고 싶다면 if 처럼 여러 개의 catch 를 사용하여 예외 별로 다른 명령을 실행시킬 수 있다.

catch(ArithmeticException e) { 
	System.out.println("ArithmeticException e");
} catch(ArrayIndexOutOfBoundsException e){
	System.out.println("ArrayIndexOutOfBoundsException e");
}

위와 같이 두 개의 catch를 사용하면, 앞선 try 로직에서 ArithmeticException 예외가 발생할 경우 1번 catch 로직이 실행되어 'ArithmeticException e' 라는 리턴값을 얻게 되며, ArrayIndexOutOfBoundsException 예외가 발생할 경우 2번 catch 로직이 실행되어 'ArrayIndexOutOfBoundsException e'라는 리턴값을 얻는다.

 

이 두 개의 예외 외에 다른 예외가 발생할 경우를 대비하고 싶다면,  세 번째 catch를 아래와 같이 사용한다면 다른 예외가 발생했을 때를 대비할 수 있다. 

catch(ArithmeticException e) { 
	System.out.println("ArithmeticException e");
} catch(ArrayIndexOutOfBoundsException e){
	System.out.println("ArrayIndexOutOfBoundsException e");
}
catch(Exception e){
	System.out.println("Excption e");
}

 

다만 Exception은 하위에 ArithmeticException ArrayIndexOutOfBoundsException을 모두 포함하므로 앞선 두 catch문보다 앞에 Exception을 catch해버려 아래 구문들이 실행될 기회조차 없어지므로 반드시 맨 마지막에 사용해야 한다.

 

 

2)  finally

try - catch 이후에 예외여부와 관계없이 실행되는 로직은 finally를 활용한다.

반드시 try-catch 이후에 사용해야 한다.

 

문법은 아래와 같다.

try {
 	예외 발생 가능성이 있는 코드;
} catch (예외클래스 인스턴스 : 매개변수 설정 ) { 
	예외가 발생했을 때 실행되는 코드;
}
finally { 
	예외 여부와 관계없이 실행되는 코드;
}

 

 

3) throw/throws : 예외 던지기

 

예외는 일종의 폭탄과 같아서 본인이 해결을 할 수도 있고 다른 사람이 해결할 수 있도록 던질 수도 있다고 한다. 

 

예를 들면 class A/ class B / class  C가 있고 B는 A를 사용, C는 B를 사용한다고 하자.

 

이 때, FileReader라는 생성자가 class A에게 Throw한 예외를 class A는 앞서 살펴본 try-catch를 이용하여 직접 해결할 수도 있지만 class A를 사용하고 있는 class B에게 다시 한 번 Throw할 수도 있다.

class B 또한, A에게 받은 예외를 같은 방법을 Class C에게 다시 Throw할 수 있는 것이다.

 

마지막 class에서도 throw를 한다면, 사용자에게 해당 예외를 넘기게 된다.

throw의 문법은 아래와 같다. 

메소드 이름 throws 예외(들);

 

4) 예외 만들어 던지기 

 

보통은 java에서 제공하는 예외 class를 읽어보고 사용하는 것을 권장한다. 내가 만들어 놓은 예외는 내가 알아보기엔 쉬울지 몰라도 다른 사람은 이런 예외를 처음 봐서 당혹스러울 수 있기 때문이다. 

하지만 그럼에도 불구하고 예외를 만들어야하는 경우, 해당 예외를 checked로 할 지 unchecked로 할 지를 정해야 한다.

(checked와 unchecked에 대한 설명은 아래 3.예외의 종류를 확인하기 바란다.)

 

그렇다면 언제 checked를 또는 unchecked를 할 것인가?

기준이 명확하게 정해진 바는 없으나 예외가 발생했을 때 사용자가 그 문제를 복구할 수 있는 경우에는 checked를 사용하고 그렇지 않을 경우에는 unchecked를 사용하는 것이 바람직하다.

Class 생성할 예외이름 extends RuntimeException {
	예외이름(){
    ;
}
예외(String message){
	super(message);
}

위의 양식은 unchecked exception을 만들기 위해 RuntimeException을 extend한 것이다. checked exception을 만들고 싶다면 부모 상속자에 RuntimeException이 없더록 extend하면 된다.

위와 같은 방법을 활용하여 특정 조건에 예외가 발생하도록 예외를 만들어 던질 수 있다. 

 

 

 

 

3. 예외의 종류

예외에 따라 compile error가 발생하여 예외처리를 하지 않으면 compile이 안되는 경우도 있는가 하면, 따로 예외처리를 하지 않아도 문제 없이 compile이 되는 경우가 있다.

어떤 특징을 가진 예외가 반드시 예외처리가 필요한지 알아보자.

 

우선 Java에서 기본적으로 제공하는 가장 상위 Class로 Throwable Class가 있다. 이 class는 이전에 살펴본 getMessage/toString/printStackTrace 와 모든 예외(Exceaption)들, 그리고 그 외에도 다양한 class를 하위(자식) class로 가진다.

아래 설명할 class 들 역시 모두 Throwable class의 하위 class이다.

 

Error : Throwable을 직접 상속하며  java virtual machine에 어떤 문제가 발생했을 때, application에게 던지는 에러.

 

Exception 

- IOException 

- RuntimeException 

 

부모 중에 RuntimeException이 있는지 없는지에 따라  각각 unchecked / checked exception이 구분된다.

부모에 RuntimeException이 있는 경우 : unchecked exception으로, 반드시 예외처리를 할 필요가 없다.

부모에 RuntimeException이 없는 경우 : checked exception으로, 반드시 try-catch나 throw를 사용해야 한다.

 

 

 

 

 

- 이클립스에서 각 생성자에 대한 도움말에 Throws가 있는 경우, 그 생성자에는 그 예외 처리를 반드시 해야함을 강제하는 것이다. (즉, checked exception인 것이다.)

예를 들면 FileReader에는 FileNotFoundException이 Throws로 있으므로 반드시 이 예외 처리를 해야한다.

 

 

 

cf) 

- getMessage : 예외 상황에 대한 아주 간단한 정보

- toString : 예외 상황에 대한 자세한 정보

- printStackTrace : 화면에 에러사항 출력

 

아래로 갈수록 상세한 정보 출력을 한다.