우테코 1주차 학습 - 예외 처리

찬디·2025년 2월 16일

우테코

목록 보기
1/18

개요

  • 어렴풋이 그냥, 다른 사람들 코드 보니까 써서, 습관적으로 작성하던 코드의 이유를 생각해보았다.

컴파일, 런타임 에러

컴파일 에러

  • 개발자에게 예외 처리를 강제하기 때문에 문제 상황을 인지할 수 있음
  • 항상 처리해줘야하니 번거롭다
    Exception 상속으로 만들수 있음

런타임 에러

  • 해당 시점에서 개발자에게 예외 처리를 강제하진 않으나 문제 상황 인지할 수 없음
  • 번거롭지 않음
    RuntimException 상속으로 만들 수 있음

컴파일 에러 처리 방식은 모든 에러를 개발자가 해소해주기 때문에 번거롭다.
RuntimeException을 잘 사용하자

예외 메시지 케이스별로 vs 통합하여

      if (name == null) {
                            throw new IllegalArgumentException("이름이 Null일 수 없습니다.");
                        }
                        if (name.isEmpty()) {
                            throw new IllegalArgumentException("이름이 빈 값 일 수 없습니다.");
                        }
                        if (name.isBlank()) {
                            throw new IllegalArgumentException("이름에 공백만 존재할 수 없습니다.");
                        }
                        if (name.length() > 5) {
                            throw new IllegalArgumentException("이름의 길이는 5자를 넘을 수 없습니다.");
                        }

위 코드가 나을까

 if (name == null || name.isBlank() || name.length() > 5) {
                            throw new IllegalArgumentException("유저 생성에 실패했습니다.");
                        }
                        return new User(name);

위 코드가 나을까?

  • 개인적인 기호라고 볼 수 있지만, 어느정도로 사용자에게 오픈할지 추상화레벨에 따라 처리하는게 좋다.
    일정부분 추상화하기
  • null,공백,빈값인 경우는 이름이 올바르지 않다 정도로 추상화할 수 있고
  • 길이 초과의 경우에는 길이 초과되었다 정도로 추상화하면 좋을 것 같다.

예외를 잘 구분 시키기

  • null,공백,빈값인 경우는 이름이 올바르지 않다 정도로 추상화할 수 있고
  • 길이 초과의 경우에는 길이 초과되었다 정도로 추상화하면 좋을 것 같다.
    위와 같이 예외를 관리하는 경우에는
    다음과 같이 예외 클래스를 따로 만드는 것도 좋겠다.
                    static class MalformedUserNameException extends IllegalArgumentException {

예외 발생시 재실행하기(복구)

상황 가정

  • 기존 객체의 특정 기능이 더이상 사용되지 않아야 할때는 어떻게하는게 좋을까?
class OldVendingMachine extends VendingMachine {
                    @Override
                    Item selectItemByName(final String name) {
                        if (ThreadLocalRandom.current().nextBoolean()) {
                            throw new IllegalStateException("아이템을 뽑는 데 실패했습니다.");
                        }

                        return super.selectItemByName(name);
                    }
                }

                final class CustomVendingMachine extends OldVendingMachine {
                    @Override
                    Item selectItemByName(final String name) {
                        try {
                            return super.selectItemByName(name);
                        } catch (final IllegalStateException e) {
                            return selectItemByName(name);
                        }
                    }
                }

위와 같이 문제가 생기는 로직에서 throw 한다면, 상위 객체에서 이를 catch해서 문제가 생기지 않는 코드가 나올때까지 호출해주면 된다.

핵심은 문제가 생겼을때 책임을 해당 객체에서 진다는 것.

복구가 아닌 회피

final class CustomVendingMachine extends OldVendingMachine {
                    @Override
                    Item selectItemByName(final String name) {
                    return super.selectItemByName(name);
                    }
                }

만약 위와같이 예외를 처리하지않고 그냥 사용한다면 회피하는 것이 된다.
책임을 외부에 준다는 것은 책임이 새어나가는 것이기 때문에 지양하는 것이 좋겠다.

의도된 회피(전환)

  • 만약 의도된 회피라면? 외부에서 해당 문제를 해결하기를 원한다면?
    그렇다면 다음과 같이 작성하면 된다.
try {
                            final var item = vendingMachine.selectItemByName(name);
                            soldItems.add(item);
                        } catch (final IllegalStateException e) {
                            throw new IllegalStateException("자판기 회사에 문의하세요.", e);
                        }

의도된 무시

  • 의도해서 무시할 수도 있겠다.
void orderFromVendingMachine(final String name) {
                        try {
                            final var item = vendingMachine.selectItemByName(name);
                            soldItems.add(item);
                        } catch (final IllegalStateException ignored) {
                            // Note: 의도된 무시기 때문에 문제가 있는 코드가 아니다.
                        }
                    }

etc

우테코에서 제공되는 코드를 많이 참고하자..
몰랐던 좋은 문법들이 많다..

ex) final class, var
테스트 코드 작성 방법 등

profile
깃허브에서 velog로 블로그를 이전했습니다.

0개의 댓글