[내일배움캠프 Spring_3기] 달리기반 4회차 - 예외처리

jiiim_ni·2026년 1월 27일

오늘은 사고에 대처하는 프로의 자세 "예외 처리(Exception Handling)"를 배웠다.

Step1: Try-Catch

// iveMembers.size()는 6
String member = iveMembers.get(10); 

아이돌 멤버는 6명인데 10번째 정보를 달라고 하면
IndexOutOfBoundsException이 발생하며 프로그램이 즉시 종료됨
뒤에 중요한 코드가 있어도 실행되지 않음

Try-Catch

이때 필요한 것이 바로 try-catch 블록
시도해보고(try), 문제 생기면 잡아라(catch)

ry {
    // 1. 위험한 행동 시도
    String member = iveMembers.get(10); 
} catch (IndexOutOfBoundsException e) {
    // 2. 예외가 발생하면 실행되는 구조 로직
    System.out.println("🚨 그런 멤버는 없습니다!");
}

NPE

String leader = null;
System.out.println(leader.length()); // 펑! 💥

존재하지 않는(Null) 객체에게 일을 시키면 NullPointerException이 발생함. 이것 또한 try-catch로 잡아서 대처할 수 있음

try {
    System.out.println(leader.length());
} catch (NullPointerException e) {
    System.out.println("🚨 리더가 없네요. 임시 리더를 뽑습니다.");
    leader = "안유진"; // 복구(Recovery)
}

요약

  • Unchecked Exception: IndexOutOfBounds, NullPointer처럼 실행 중에 뜬금없이 터지는 에러들
  • Handling: 에러를 잡아서 로그를 남기거나, 다른 값으로 대체하는 등 수습을 하는 과정

Step2: Checked Exception

// ❌ 컴파일 에러 발생!
Thread.sleep(1000); 

Unhandled exception: java.lang.InterruptedException"

(해석: 야, 자다가 누가 깨우면 어떡할 거야? 대책 세워놨어?)

자바는 예측 가능한 위협에 대해서는 반드시 안전장치(try-catch) 를 마련하라고 강요

try-catch

try {
    for (int i = 3; i > 0; i--) {
        System.out.println(i + "초...");
        Thread.sleep(1000); // 1초간 잠듬
    }
    System.out.println("🎉 컴백!");

} catch (InterruptedException e) {
    // 혹시라도 자다가 누가 깨웠을 때(Interrupt) 실행될 코드
    System.out.println("😴 으악! 누가 깨웠어!");
}

이처럼 Exception 클래스를 직접 상속받는 예외들은 모두 Checked Exception

요약

  • Unchecked Exception: 실수하면 터지니까 조심해.(자율)
  • Checked Exception: 위험하니까 무조건 처리해.(강제)
    프로그램이 치명적인 상황(파일 입출력 오류, 네트워크 끊김 등)에서도 살아남을 수 있게 해주는 최소한의 안전장치

Step3: Throw

직접 에러를 만들어 던지는(throw)방법

Return

public boolean buyTicket(int money) {
    if (money < 10000) {
        return false; // "실패했어 (소곤소곤)"
    }
    // ... 예매 로직 ...
    return true;
}
  • 이 방식의 문제는 무시할 수 있다는 것임
    호출하는 쪽에서 if(buyTicket(...))검사를 까먹으면 실패했는데도 불구하고 성공한 줄 알고 다음 코드가 실행됨(Silent Failure)

Throw

public void buyTicket(int money) {
    if (money < 10000) {
        throw new RuntimeException("돈 없어! 나가!"); // "실패!!! (와장창)"
    }
    // ... 예매 로직 ...
}

에러를 던진다는 것은 비상벨을 울리는 것과 같음
호출하는 쪽에서 귀를 막고 싶어도 막을 수가 없음. 프로그램이 멈춰버리기 때문에, 개발자는 강제적으로 이 상황을 처리(catch) 해야만 함

결론

throw는 단순히 에러를 내는 게 아니라, 이대로 진행하면 더 큰 사단이 나니까 여기서 멈춰! 라고 외치는 방어 수단
1. Return: 실패했어. 보고 들을지는 너 맘이야(수동적)
2. Throw: 실패했어! 당장 처리해!(능동적/강제적)


Step4: Custom Exception

Unchecked

// extends RuntimeException: 실행 중에 발생하는 상태 문제
public class NotEnoughFanPowerException extends RuntimeException { ... }
  • 그냥 RuntimeException을 던지는 것보다, NotEnoughFanPowerException을 던지면 로그만 봐도 돈 문제인 것을 바로 알 수 있음

Checked

// extends Exception: 꼭 처리해줘야 하는 중요한 문제
public class IdolNotFoundException extends Exception { ... }
  • 중요한 비즈니스 로직(결제, 검색 등)은 강제로 try-catch를 시키기 위해 Checked Exception으로 만듬

Multi-catch

try {
    buyTicket("BlackPink", 50000);

} catch (IdolNotFoundException e) {
    // 검색 오류 -> 다시 검색 유도
    System.out.println("아이돌 이름을 다시 확인해주세요!");

} catch (NotEnoughFanPowerException e) {
    // 결제 오류 -> 충전 유도
    System.out.println("팬심을 충전하고 다시 오세요!");

} catch (Exception e) {
    // 그 외 알 수 없는 오류 -> 고객센터 연결
    System.out.println("고객센터에 문의하세요.");
}

만약 모든 에러를 Exception e 하나로 퉁쳤다면?
고객에게 뭔가 잘못됐어요 라는 말밖에 해주지 못함.


Step5: Optional

// "아이돌을 찾아 줄 건데, 없을 수도 있어(Optional)!"
public Optional<Idol> findByNameOptional(String name) {
    return Optional.ofNullable(db.get(name));
}

이렇게 Optional 이라는 상자에 포장해서 주면
사용하는 쪽에서는 강제적으로 상자를 열어봐야함
그냥 idol.getName()을 할 수 없게 됨 -> 아주 안전

1. ifPresent: 있으면 실행해!

// 상자에 값이 있으면 꺼내서 인사 시키기
optionalIdol.ifPresent(idol -> System.out.println(idol.getGreeting()));

2. orElse: 없으면 이걸 써!(기본값)

// 상자가 비어있으면 '연습생' 객체를 대신 씁니다.
Idol idol = optionalIdol.orElse(new Idol("연습생", "무소속"));

3. orElseThrow: 없으면 에러다!(엄격 모드)

// 반드시 있어야 하는 값이라면, 없으면 에러를 던지게 할 수도 있습니다.
Idol idol = optionalIdol.orElseThrow(
    () -> new RuntimeException("누구세요?")
 );

4. map: 꺼내지 말고 안에서 변환해!(강추)

// 아이돌 객체 -> 팀 이름(String)으로 변환 (없으면 "팀 없음")
String teamName = optionalIdol
    .map(Idol::getTeam)
    .orElse("팀 없음");

상자에서 굳이 꺼내지(get) 않고도 내용을 바꿀 수 있음

Optional 팁

  1. Optional을 리턴하면서 null을 주지 마라!
  • 상자를 주기로 해놓고 또 빈 손을 주는 꼴. 무조건 Optional.empty()를 리턴해야함
  1. 필드나 파라미터에는 Optional 쓰지 마라!
  • Optional은 오직 리턴 타입으로만 쓰라고 만든 것. 클래스 필드에 Optional 쓰면 직렬화도 안되고 메모리만 더 먹음
  1. 무조건 Optional이 답은 아님
  • 리스트나 배열을 리턴할 때는 Optional<List<T>> 하지 말고, 그냥 빈 리스트(Collections.emptyList())를 주는 게 훨씬 깔끔

메서드에서 Null을 리턴하는 습관을 버리기!
대신 비어있을 수 있음을 뜻하는 Optional 리턴하기

4일동안 객체지향, 람다, 스트림, 예외처리에 대해서 배웠다.
튜터님의 설명이 귀에 쏙쏙 박혀서 정말 유익한 시간이었다.

0개의 댓글