프로그램 오류?
프로그램이 실행 중 어떠한 원인으로 인하여 오작동하거나 비정상 종료 될 시 이와같은 결과를 초래하게 만드는 원인을 프로그램 에러 또는 오류라 한다.
컴파일 에러 : 컴파일 시점에서 발생하는 에러
런타임 에러 : 프로그램이 실행하는 중 발생하는 에러
논리적 에러 : 정상실행은 되지만, 예상과 다르게 동작하는 에러
에러 , 예외 ?
에러 : 프로그램 코드 레벨에서 수습할 수 없는 심각한 오류
예외 : 프로그램 코드 레벨에서 수습할 수 있는 경미한 오류
예외 클래스 계층구조도 ?

다음과 같이 여러가지 예외처리를 위한 예외클래스 계층구조를 확인해 볼 수 있다. 이때, 우리 코드 상에서 잡을 수 있는 오류인 예외는 Exception(=checked예외)을 최상위 부모로하여 RuntimeExcetion(=unchecked예외)을 상속받는 클래스들은 런타임 시 발생하는 예외를 이외에는 컴파일 시 발생할 수 있는 예외들로 구분되어 있다.
이때, 컴파일 시 발생하는 예외들은 반드시 사전에 예외처리 관련 코드를 추가하지 않을 경우 컴파일 조차 할 수 없기에 반드시 추가해야한다면 런타임 시 발생하는 예외의 경우는 반드시 예외처리를 해주지 않아도 컴파일 시 문제가 발생하지 않고 정상 작동한다. 그러나 예외처리를 하지 않았기에 예외가 발생시 프로그램은 비정상 종료된다.
예외처리하기 ?
예외처리란, 프로그램 실행 중 발생할 수 있는 예기치 못한 예외 발생에 대비하여 코드를 작성하여 예외로 인한 프로그램 비정상 종료를 막고, 정상적인 실행상태를 유지시키기 위함이다.
예외처리를 하지 않아 발생한 예외로 프로그램이 비정상 종료될 시 처리되지 못한 예외는 JVM의 '예외처리기(UncaughtExceptionHandler)'가 받아서 예외 원인을 화면에 출력한다.
1) try - catch 문
try{
// 예외가 발생할 수 있는 코드를 넣는다.
}catch(Exception1 e1){
// Exception1타입 에러 발생 시 처리할 문자
}catch(Exception2 e2){
// Exception2타입 에러 발생 시 처리할 문자
}catch(Exception3 e3){
// Exception3타입 에러 발생 시 처리할 문자
}
.
.
발생가능한 예외들 추가
흐름 ?
👉 try블럭 내에서 예외가 발생할 경우
1. 발생 원인에 대한 예외 클래스의 인스턴스가 생성된다.
2. 가장 위 catch문부터 시작하여 참조변수 타입과 생성된 인스턴스 사이에 instance of 참조타입 비교를 수행한다.
👉 만약 일치하는 catch문이 없을 시 처리되지 못한 예외에 의해서 프로그램이 비정상 종료된다.
3. 일치하는 catch문이 있을 시 내부의 작업을 수행한다.
4. 작업을 완료할 시 try - catch문을 빠져나온다
👉 try블럭 내에서 예외없이 완료할 시
1. try - catch문을 빠져나온다.
2. try - catch문 다음 작업을 계속 수행한다.
printStackTrace() ,getMessage() ?
printStackTrace() : 예외발생 당시의 호출스택에 있었던 메서드의 정보와 예외 메세지를 화면에 출력
getMessage() : 발생한 예외클래스의 인스턴스에 저장된 메세지를 얻을 수 있다.

2) 멀티 catch블럭
JDK1.7부터 catch블럭을 '|'기호를 이용해서 여러개의 catch블럭을 하나로 합칠 수 있다.
이때, 주의할 사항은 함께 묶이는 예외클래스 사이에는 상속관계인 클래스는 묶을 수 없으며, 함께 묶이는
클래스들 중 어떠한 에러가 발생하는지는 알 수 없기에 조상 예외 클래스에 선언된 멤버만 사용 가능하다.
만약 해당 예외클래스 멤버를 사용하고 싶을 경우 내부적으로 형변환을 하여 사용할 수는 있다.
try{
// 예외발생 가능성 있는 구현 코드
}catch(ExceptionA | ExceptionB e){
e.methodeExceptionAType() // ExceptionA클래스에만 있는 메서드 사용 할 수 x
}
다음을 사용하는 경우는 여러개의 예외처리에 있어서 공통으로 묶어서 동일하게 처리하고 싶을 경우에 활용할 수 있다.
3) 메서드에 예외 선언하기
/*
다음과 같이 메서드에 발생할 수 있는 예외들을 적을 수 있다.
실제 예외발생 시 해당 메서드에서 예외를 처리하지 않고 해당 메서드를 호출한 메서드로
예외를 넘긴다
*/
void exceptMethod() throws 예외클래스1,예외클래스2,.....{
//메서드 내용
}
다음과 같이 예외발생 시 예외가 발생한 메서드 내부적으로 처리하는 것이 아닌 호출한 쪽으로 예외를 넘길 수 있다. 이때, 발생할 수 있는 예외에 대해서는 보통 컴파일 단계 예외를 기입하며, 런타임 시 발생 할 수 있는 예외는 제외하여도 실행 시 문제가 없다. 물론 런타임 예외가 발생하면 처리해주어야한다.
다음과 같이 메서드를 통해서 예외를 떠넘길 경우 반드시 호출스택 상 있는 어딘가에서는 반드시 처리를 해주어야하며 main메서드까지 처리가 안될 시 예외에 의한 비정상 종료가 된다.
4) finally 블럭
finally블럭은 예외의 발생여부와 상관없이 실행되어야하는 코드를 포함시킬목적으로 사용된다.
try{
// 예외발생 가능성 있는 구현 코드
}catch(Exception e){
// 해당 예외 발생 시 처리할 코드
}finally{
/*
- 예외의 발생과 상관없이 마지막에 반드시 수행되는 코드
- try - catch문 마지막에 위치해야한다.
- try문에서 자원을 사용한 후 예외발생여부와 상관없이 자원은 반납되어야한다.
이럴때 해당 위치에서 자원을 반납해주면 예외 상관없이 반납된다.
*/
}
5) try - with - resources 문
JDK1.7부터 새로 추가되었으며, 주로 I/O 관련 클래스 사용 시 유용하게 사용할 수 있다.
/*
try - with - resources을 통해서 자원을 사용 후 자동반납하기 위해서 해당 클래스는
AutoCloseable 인터페이스에 close()를 구현해야한다.
*/
public interface AutoCloseable{
void close() throws Exception;
}
// try - with - resources 구문 사용
try ( FileInputStream fis = new FileInputStream("test.txt") ; // 여러 자원 사용 시 ;로 구분
DataInputStream dis = new DataInputStream(fis)){
// 예외발생 가능한 코드
}catch(Exception e){
}catch(Exception2 e){
}


위에 코드에서 사용한 자원에 대해서 부모클래스로 올라가보면 InputStream 클래스에서 Closeable 인터페이스의 close()를 구현한 것을 확인할 수 있다.
예외 만들기 및 발생시키기 ?
1) 예외 발생 시키기
throw 키워드를 사용하면 예외를 발생시킬 수 있다.
public static void main(String[] args) {
try{
ArithmeticException e = new ArithmeticException(); // 발생시킬 예외 인스턴스 생성
throw e; // throw 키워드를 사용해서 예외발생
// throw new ArithmeticException(); 한 줄로 표현
}catch (ArithmeticException e){
System.out.println("getMessage() : "+e.getMessage());
System.out.println();
System.out.print("printStackTrace() : ");
e.printStackTrace();
}
}

다음과 같이 예외가 발생하는 것을 볼 수 있다. 그러나 한 가지는 예외메세지가 null인 것을 볼 수 있다. 임의로 만들어서 발생시킬경우 메세지가 없는 것 같다. 이럴때 인스턴스 생성 시 생성자 매개변수로 예외메세지를 String 형태로 지정해줄 수 있다.
2) 사용자정의 예외 만들기
보통 Exception클래스 또는 RuntimeException클래스로부터 상속받아 만들지만, 필요에 맞게 상속할 예외클래스를 선택하여 사용할 수 있다.
//사용자정의 예외 만들기
class MyException extends Exception{
MyException(String msg){
super(msg);
}
}
public class Main {
public static void main(String[] args) {
try{
throw new MyException("사용자 예외 만들기");
}catch (MyException e){
System.out.println("getMessage() : "+e.getMessage());
System.out.println();
System.out.print("printStackTrace() : ");
e.printStackTrace();
}
}
}

'P.L > Java' 카테고리의 다른 글
열거형(enums) (0) | 2023.03.26 |
---|---|
유용한 배열 사용 - java.util.Arrays 클래스 (0) | 2023.02.08 |
java.lang.Character 클래스 (0) | 2023.01.28 |
java.util.Arrays 클래스를 활용한 배열복사 (0) | 2023.01.19 |
String 클래스 - repeat() (0) | 2022.12.20 |