예외적인 상황을 대비 한 코드를 미리 만들어 두어서 문제 발생시 좀 더 안정적인 구조를 제공하여 문제 해결에 필요한 정보를 제공 받을 수 있다.
일반적으로 프로그램에서 발생하는 에러는 컴파일 과정 중 발생하는 컴파일 에러와 실행 중 발생하는 런타임 에러로 구분된다.
컴파일 에러는 소스 작성과정 중에 대부분 발견된다.
런타임 에러는 프로그램 로직 상에 문제나 실행 중 부적절한 데이터 혹은 자료구조 객체 참조 등으로 발생된다.
try~catch 블럭
자바에서 기본적인 예외 처리 방법은 try ~ catch 블럭을 사용하는 것이다. 그렇다면 언제 사용해야할까?
예외상황은 이럴 때 생겨난다고 볼 수 있다.
1. 특정 파일을 로딩하려고 하는 해당 경로에 파일이 없는 경우
2. 네트워크 서버에 접속하는 경우 서버에서 500 번대 status를 주거나 네트워크 자체 연결에 문제가 생기는 경우
3. 문자열 데이터를 읽어 객체의 참조를 구하는 경우
4. 정수를 0으로 나누는 경우
여기서 throws 구문을 추가하면 특정 예외 상황 처리를 강제할 수 있다.
예외 처리 클래스는 java.lang.Exception 클래스를 부모로 하는 대표적인 클래스 들이 있고 예외 클래스를 커스텀하려면
Exception 클래스를 상속받아서 구현하면 된다.
예외 처리 유형?
예외 처리 유형에는 Checked 와 Unchecked 가 있다.
- Checked Exception
Exception 클래스를 상속 받아 구현된 클래스
컴파일러에 의해 강제로 예외 처리 ( try~catch ) 구문 처리가 요구된다.
- UnChecked Exception
RuntimeException 클래스를 상속받아 구현된 클래스
강제로 예외처리가 요구되지는 않지만 필요에 따라 예외 처리가 가능하다.
파일 데이터를 읽어 출력하는 IO 프로그램 구현하면서 예외 처리 과정 익히기
import java.io.File;
import java.util.Scanner;
// 예외처리 전
public class ExceptionTest {
public static void main(String[] args) {
File file = new File("test.txt");
Scanner Scan;
scan = new Scanner(file);
while (scan.hasNext()) {
System.out.println(scan.next());
}
}
}
// 예외처리 후
public class ExceptionTest {
public static void main(String[] args) {
File file = new File("test.txt");
Scanner Scan;
try {
scan = new Scanner(file);
while (scan.hasNext()) {
System.out.println(scan.next());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
조금 더 효율적인 예외처리
try {
method1();
}
catch (AAAEception e) {
...
}
try {
method2();
}
catch (BBBException e) {
...
}
보다는
try {
method1();
method2();
}
catch (AAAEception e) {
...
}
catch (BBBException e) {
...
}
이 더 나은 방법의 예외 처리가 될 수 있다.
만일 두개의 예외에 대해 동일한 처리를 한다고 가정하면 다음과 같이 예외들을 묶을 수 있다.
catch (AAAEception | BBBException e) {
...
}
이경우에서 만일 두 예외가 부모 자식 관계라면 부모 클래스만 명시해 주어야 한다.
혹은 여러 예외의 처리가 동일하다고 하면 그냥 최상위 클래스인 Exception 만 처리해도 같은 효과가 있다.
catch(Exception e) {
...
}
예외처리 흐름과 처리 내용
예외 처리는 try 블럭 안에 있는 코드들이 차례로 실행되며 예외가 발생한 구문 이후의 코드들은 실행되지 않고
catch 블럭에서 해당 예외 처리를 따른다.
보통 예외 처리 블럭에서는 예외상황을 추적하기 위해 e.printStackTrace() 메서드를 사용해 콘솔에 예외상황을 출력해 문제를 해결하기 위한 도움 메시지로 활용하거나 좀 더 체계적으로 관리하기 위해서 로거를 통해 로그를 남기는 형태로 구현하는 것이 좋다.
finally
finally 는 예외가 발생한 경우나 혹은 발생하지 않은 경우 모두 수행되는 블럭을 지정할 때 사용한다. 코드의 성공/실패 여부에 상관없이 반드시 실행되어야 하는 구문들이 있다면 finally에 넣어줘야 한다.
try {
method1();
method2();
}
catch (AAAEception e) {
...
}
catch (BBBException e) {
...
}
finally {
...
}
예외 던지기와 예외 클래스 작성
메서드에 예외 처리를 강제하도록 하는 방법을 알아본다.
메서드를 만들 때 throws 구문을 넣어주면 현재 메서드에서 특정 예외 처리를 하지 않겠다는 의미가 된다.
해당 메서드를 호출하는 쪽에서 해당 예외 클래스에 대한 처리 즉 try ~ catch 블럭을 사용해야 한다는 것을 의미한다.
이 방법은 개발자가 만드는 메서드를 호출 할때 특정 예외 처리를 강제하도록 하는데에도 사용되며, 자신이 만든 전용의 예외 처리 클래스를 활용할 때도 적용된다.
public void printData() throws IOException, MyException {
}
- printData() 메서드 안에서 IOException 을 발생시키는 메서드를 사용할 경우 자체 처리를 하지 않고 호출하는 쪽으로 예외처리를 넘김.
- 제공되는 예외클래스 이외에 내가 만든 예외클래스 역시 throws 할 수 있음.
직접 예외 클래스를 만드는 경우 Exception 혹은 RuntimeException 클래스를 상속받아 구현하면 된다.
해당 예외는 예를 들면 앞의 printData() 메서드내에서 특정상황에 throw MyException 코드를 작성함으로써 예외 코드를 동작시킬 수 있습니다.
public class ExceptionTest2 {
int num;
public void doExeption() throws MyException {
if (num == 1)
System.out.println("OK");
else
throw new MyException("doException");
}
public static void main(String[] args) {
ExceptionTest2 app = new ExceptionTest2();
app.num = 2;
try {
app.doExeption(); // 호출하는 쪽에서 예외 처리 진행
} catch (MyException e) {
e.printStackTrace();
}
}
}
'java' 카테고리의 다른 글
제네릭이란 무엇인가? ( Generics ) (0) | 2021.01.21 |
---|---|
문자열 다루기? (0) | 2021.01.21 |
제어자? (0) | 2021.01.20 |
오버로딩과 오버라이딩 (0) | 2021.01.19 |
자바 메모리 관리 ? (0) | 2021.01.19 |