인프런 커뮤니티 질문&답변

cobox님의 프로필 이미지
cobox

작성한 질문수

스프링 핵심 원리 - 기본편

스프링 Checked Exception/ Unchecked Exception에 대한 질문입니다.

해결된 질문

작성

·

241

0

안녕하세요. 강의 잘 듣고 있습니다. 코드 작성하다가 예외처리에 대한 궁금증이 있어 질문드립니다.

제가 알고있는 스프링 예외처리 정책은 Unchecked Exception은 같은 트랜잭션 내에서 Rollback 되고 Checked Exception은 필수로 try catch로 예외처리를 해서 Rollback이 안되는 것으로 알고 있습니다.

Unchecked Exception도 try-catch로 잡아서 예외를 처리하려고 하는데 Unchecked Exception은 Checked Exception과는 다르게 중간에서 예외를 잡아도 가장 상위 메소드로 올라가서 예외가 발생되더라구요. 때문에 최상위 메소드에서 try-catch로 잡아줘야지만 예외가 잡히고 다음 스텝으로 넘어가던데 왜 중간에서 try - catch로 잡히지 않는 것인지 궁금합니다. 간단한 코드 첨부하겠습니다.

class A {
    @Autowired
    private B b;

    @Transactional
    void aMethod(){
        for(int i=0; i<10; i++){
            b.bMethod(i);
        }
    }
}
class B {
    @Autowired
    private C c;

    @Transactional
    void bMethod(int i){
        try{
          c.cMethod(i);
        }catch(RuntimeException e){
          //예외처리로직
        }
    }
}
class C {
    @Autowired
    private CRepository cRepository;

    @Transactional
    void cMethod(int i){
        if(i==5){
            throw new RuntimeException();
        }else{
             cRepository.save(i);
        }
    }
}

위의 코드를 실행하면 B class의 try catch가 C에서 발생한 RuntimeException을 잡아서 계속 직행하지 못하고 A까지 예외가 올라가서 예외가 발생됩니다.

try catch 블록을 A class로 옮기면 예외를 잡아서 console에 예외가 터지지 않고 정상 작동됩니다.

Checked Exception은 저렇게 중간에 예외를 잡아도 예외가 상위 메소드로 올라가지 않고 처리되던데 Unchecked Exception은 왜 최상위 메소드까지 올라가서 처리를 해줘야하는지 궁금합니다.

답변 1

0

안녕하세요, 인프런 AI 인턴이에요. Checked Exception과 Unchecked Exception에 대한 질문이실 거 같아 답변드릴게요.

스프링에서 Checked Exception과 Unchecked Exception에 대한 처리 정책은 다르게 적용됩니다.
Checked Exception은 컴파일 시점에서 확인되는 예외로, 반드시 try-catch 블록을 사용하여 예외를 처리하거나 throws 구문을 통해 예외를 던져야 합니다. 이 경우 예외가 체크되어 롤백되지 않는 트랜잭션 내에서 발생하게 됩니다.
반면 Unchecked Exception은 런타임 시점에서 확인되는 예외로, 명시적인 예외처리를 강제하지 않습니다. 따라서 예외를 발생시키고자 할 때 try-catch 블록을 사용하지 않아도 됩니다. 그래서 Checked Exception과는 달리 중간에서 예외를 잡아도 가장 상위 메소드로 예외가 전파되는 것이 맞습니다.

코드를 살펴보면, aMethod에서 bMethod를 호출하고, bMethod에서 cMethod를 호출하고 있는데, cMethod에서 발생한 예외를 bMethod에서 try-catch로 처리하고 있습니다.
하지만 cMethod를 호출할 때, 예외가 발생하면 해당 예외는 bMethod로 전파되며, bMethod도 예외를 처리하지 않으면 aMethod로 전파될 것입니다. 따라서 최상위 메소드인 aMethod에서 예외를 처리해야 합니다.

만약 중간 메소드에서 예외를 처리하고 싶은 경우, catch 블록에서 예외를 다시 던져주어야 합니다. 이렇게 하면 호출 스택을 타고 전파되는 예외를 중간에서 처리할 수 있을 것입니다. 코드에서는 bMethod에서 cMethod를 호출할 때, catch 블록에서 예외를 처리하고 해당 예외를 다시 던지는 방식으로 중간에서 예외를 처리할 수 있습니다.

코드에 대한 예외 처리 방식을 수정해보면 아래와 같을 것입니다.

class B {
    @Autowired
    private C c;

    @Transactional
    void bMethod(int i){
        try{
            c.cMethod(i);
        }catch(RuntimeException e){
            // 예외처리로직
            throw e; // 예외를 다시 던져줌
        }
    }
}

이렇게 하면 예외가 cMethod에서 발생해도 bMethod에서 예외가 처리되고, aMethod로 전파되지 않을 것입니다.

더 궁금한 점이 있다면 언제든지 물어보세요!

cobox님의 프로필 이미지
cobox

작성한 질문수

질문하기