Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

블로그 이름 뭐하지

[JAVA] 예외 처리 본문

JAVA

[JAVA] 예외 처리

가는말이고우면오는말은come 2024. 9. 24. 12:03

예외

오류와 예외의 차이

오류(Error) : 일반적으로 회복이 불가능하다

보통 시스템 레벨에서, 또는 환경적인 이유로 발생한다

ex. 메모리 부족(OutOfMemoryError), 스택오버플로우(StackOverflowError)...

 

예외(Exception) : 일반적으로 회복이 가능하다

(= 예외 발생을 인지하고 대응이 가능함)

코드 레벨에서 발생하여 문제 상황에 대한 처리가 가능하다

ex. 비정상적인 연산처리(ArithmeticException), Null 객체 참조(NullPointException)...

 

예외의 종류

 

1. 코드 실행 관점

1) 컴파일 에러(예외)

.java파일을 .class파일로 컴파일 할 때 발생한다

대부분 자바 언어의 규칙을 따르지 않아 발생한다.

문법에 맞게 다시 작성하는 것으로 해결한다.

프로그래머의 실수로 발생한다고 생각하면 이해하기 쉽다

ex. 존재하지 않는 파일 이름입력(FileNotFoundException),

클래스의 이름 잘못 기재(ClassNotFoundException),

입력한 데이터 형식이 잘못됨(DataFormatException)...

 

2) 런타임 에러(예외)

문법적 오류가 아니라서 컴파일은 성공했지만,

프로그램이 실행 도중 마주하게 되는 예외이다.

사용자의 실수와 같은 외적인 요인으로 발생한다고 생각하면 이해하기 쉽다.

ex. 배열의 범위를 벗어남(IndexOutBoundsException)

값이 Null인 참조변수의 멤버 호출(NullPointerException)

클래스 간의 형변환 오류(ClassCastException)

정수를 0으로 나누는 등의 산술 오류(ArithmeticException)

 

2. 예외 처리 관점

1) 확인된 예외(Checked Exception)

컴파일 시점에 확인하는 예외이다.

반드시 예외처리가 필요하다.

여기에 관한 예외처리를 하지 않으면 컴파일 에러가 발생한다.

예외 발생시 롤백하지 않는다.

 

2) 미확인된 예외(Unchecked Exception)

런타임 시점에 확인되는 예외이다.

예외처리가 반드시 필요하지 않다.

예외 발생시 롤백한다.

 

예외처리

1. 예외정의하기

클래스와 메서드를 이용해 개발자 스스로 예외를 정의 할 수 있다.

//Exception클래스에 상속받는 예외 클래스 만들기
class OurBadException extends Exception {
	public OurBadException() {
		super("위험한 행동을 하면 예외처리를 꼭 해야합니다!");
	}
}

 

2. 예외가 발생할 수 있음을 알림

예외를 예측했다면, 해당 메서드에 예외가 발생할 수 있음을 알린다.

이때 throws와 throw 예약어를 사용한다.

 

throws : 메서드 이름 옆에 붙어 해당 메서드가 어떤 예외 사항을 던질 수 있는지 알려준다

여러가지 예외사항을 적을 수 있다.

throw :  메서드 내에서 실제로 예외 객체를 던질 때 사용한다.

실제로 던지는 예외 객체 하나와 함께 사용한다.

return 키워드처럼 throw 아래 구문은 실행되지 않고 메서드가 종료된다.

class OurClass {
    private final Boolean just = true;
	//throws: 메서드가 어떠한 예외사항을 던질 수 있는지 알려준다		
    public void thisMethodIsDangerous() throws OurBadException {
        if (just) {
        //throw: 메서드 안에서 예외객체를 던질 때 사용한다.
            throw new OurBadException();
        }
    }
}

 

3. 위험한 메서드일 경우 예외를 handling

특정한 메서드가 위험할 경우(예외가 발생할 가능성이 있는 경우) try-catch 키워드로 예외를 처리한다.

 

try{}

중괄호안에 예외가 발생할 가능성이 있는 코드를 기입하여, 실행을 '시도'한다.

catch(예외 e){}

소괄호 안에는 실행시 발생할 예외클래스를 기입하여 정의한다

모든 예외를 다 받고 싶으면 Exception을, 일부 예외만 받고 싶으면 해당 예외 클래스 명을 기입한다.

하나의 try문에 catch문은 여러개 사용할 수 있다.

중괄호 안에는 예외가 발생할 경우 실행할 코드를 기입하여 예외를 '잡는다'.

finally{}

중괄호 안에 예외의 발생 여부와 상관없이 실행시킬 코드를 기입한다.

에외가 발생하든 하지않든, 무조건 실행되는 코드이며, 생략이 가능하다.

public class StudyException {
    public static void main(String[] args) {
        OurClass ourClass = new OurClass();

        try {
            // 1. 위험한 메소드의 실행을 시도
            ourClass.thisMethodIsDangerous();
        } catch (OurBadException e) {
            // 2. 예외가 발생하면, "잡아서" handling
            // 예외가 발생하는경우 "handling" 하는 코드가 들어가는 블럭.
            // 즉 try 블럭 내의 구문을 실행하다가 예외가 발생하면
            // 예외가 발생한 줄에서 바로 코드 실행을 멈추고
            // 여기 있는 catch 블럭 내의 코드가 실행됨.
            System.out.println(e.getMessage());
        } finally {
            // 3. 예외의 발생 여부와 상관없이, 실행시켜야 하는 코드.
            System.out.println("우리는 방금 예외를 handling 했습니다!");
        }

    }
}

 

 

Chained Exception

 

여러가지 예외를 연결하여 큰 분류의 예외로 묶어 다루는 방식이다.

checked exception을 unchecked exception으로 포장(wrapping)하는데 유용하다

 

예외는 다른 예외를 발생시킬 수 있다.

예외 A가 예외 B를 발생시킨다면 예외 A는 B의 원인 예외이다.

원인 예외를 새로운 예외에 등록 시킨 후 다시 새로운 예외를 발생시키는 것을 예외 연결이라고 한다.

 

원인 예외를 다루기 위한 메서드

initCause() : 지정한 예외를 원인 예외로 등록함

getCause() : 원인 예외를 반환함

 

// 연결된 예외 
public class main {

    public static void main(String[] args) {
        try {
            // 예외 생성
            NumberFormatException ex = new NumberFormatException("가짜 예외이유");

            // 원인 예외 설정(지정한 예외를 원인 예외로 등록)
            ex.initCause(new NullPointerException("진짜 예외이유"));

            // 예외를 직접 던짐
            throw ex;
        } catch (NumberFormatException ex) {
            // 예외 로그 출력
            ex.printStackTrace();
            // 예외 원인 조회 후 출력
            ex.getCause().printStackTrace();
        }

        // checked exception 을 감싸서 unchecked exception 안에 넣음
        throw new RuntimeException(new Exception("이것이 진짜 예외 이유 입니다."));
    }
}

// 출력
Caused by: java.lang.NullPointerException: 진짜 예외이유

 

 

실제 예외처리 방법

 

1. 예외 복구

예외 발생 시 일정 시간 대기 후 재 접속을 시도하거나,

다른 비즈니스 로직 흐름으로 유도시키거나,

예외가 발생하지 않는 상황으로 복구를 시도하는 로직을 추가한다.

현실적으로는 복구가 불가능한 상황이거나 최소한의 대응만 가능한 경우가 많아 자주 사용하지는 않는다.

	int maxretry = 5;

        while(maxretry -- > 0){
            try{
                //예외 발생 가능성이 있는 코드
            }catch(Exception e){
                //로그 출력 및 정해진 시간만큼 대기
            }finally {
                //리소스 반납 및 정리작업
            }
        }

        throw new InternalException("에러가 발생하였습니다.");

 

2. 예외 회피

예외처리를 자신을 호출한 쪽으로 던진다.

이 경우 무책임한 책임 회피가 될 수 있으므로,

호출부분에서 예외를 처리하는 것이 더 바람직한 경우이거나

해당 로직이 예외를 회피하는 것이 낫다는 확신이 들 경우에만 사용해야한다.

예외를 어느정도 처리하고 던지는 것도 하나의 방법이다.

    public static void exceptionEvasion() throws SQLException{

        try{
            /// JDBC API
            throw new SQLException();
        }catch(SQLException e){
            throw e;
        }
    }

 

3. 예외 전환

예외 회피와 비슷하나, 조금 더 적절한 예외를 던져준다.

1) 발생된 예외가 해당 상황에 대해 적절한 의미를 부여하지 못하거나,

2) CheckedException을 UncheckedException으로 포장할 때 사용한다.

1)

// 회원가입 메서드를 호출하는 메서드
public static void requestJoin(User user){
    try{
    	join(user);
    }catch(SQLException e){
    	// 예외 처리를 해야하는데, SQLException이 왜 발생한거지? 내부 로직을 확인해봐야겠다..
    }
}

// 회원가입 메서드
public static void join(User user) throws SQLException{

    // 1. 회원가입 로직 ...
    // 2. ID, PW 정보 DB INSERT 시 ID 중복(무결정 제약조건 위배)되어 SQLException 발생
    // 3. 메서드 시그니처의 throws SQLException 을 통해 예외 throw
}

-------------------------------▽

// 회원가입 메서드를 호출하는 메서드
public static void requestJoin(User user){
    try{
    	join(user);
    }catch(DuplicateUserIdException e){ // ID 중복이 발생할 수 있구나!
    	// 예외 처리
    }
}

// 회원가입 메서드
public static void join(User user) throws DuplicateUserIdException{

    try{
        // 1. 회원가입 로직 ...
        // 2. ID, PW 정보 DB INSERT 시 ID 중복(무결정 제약조건 위배)되어 SQLException 발생
    }catch(SQLException e){
        throw new DuplicateUserIdException(e);  // 3. DuplicateUserIdException 예외 throw
    }      
}

예시코드 : 회원가입시 ID가 중복되는 에러(SQLException) 발생
>> SQLException만으로는 원인을 찾기가 어려움
>> DuplicateIdException 예외로 전환
>> ID가 중복되었다는 의미를 담고 있어 원인파악이 수월함
2)

try{
    OrderHome orderHome = EJBHomeFactory.getInstance().getOrderHome();
    Order order = orderHome.findByPrimaryKey(Integer id);
}catch(NamingException ne){
	throw new EJBException(ne);
}catch(SQLException se){
	throw new EJBException(se);
}catch(RemoteException re){
	throw new EJBException(re);
}

//EJBException은 런타임예외(Unchecked Exception)고,
//나머지 예외들은 checked Exception이다.
//자동롤백을 사용하기 위해 checked Exception을 런타임예외로 포장한다.

'JAVA' 카테고리의 다른 글

[JAVA] 쓰레드  (0) 2024.09.25
[JAVA] 제네릭  (0) 2024.09.24
[JAVA] 추상 클래스와 인터페이스  (0) 2024.09.23
[JAVA] 상속  (0) 2024.09.23
[JAVA] 클래스  (0) 2024.09.23