1️⃣ 오늘의 Keyword
- null
- Optional
- try-catch
- Exception
- Result
2️⃣ 학습 내용 및 예시
null
null이란?
- 아무 객체도 가리키지 않는 값
null의 문제점
- 컴파일 시점에서 잡히지 않고 런타임에 발생하여 디버깅이 어려움
- if문을 사용해 일일이 체크하면 가독성이 떨어지고 실수 확률이 높음
String name = null; System.out.println(name.length()); // 💥 NPE 발생
if (user != null) { if (user.getAddress() != null) { if (user.getAddress().getCity() != null) { System.out.println(user.getAddress().getCity()); } } }
Optional
Optional이란?
- null의 문제점을 보완하기 위해 자바에서 만든 도구
- null을 없애는 것이 아니라, null을 의식하게 만들기 위한 장치
Optional 초기화 방법
Optional.of(value)— 값이 무조건 있어야 함
Optional.ofNullable(value)— null일 수도 있을 때
Optional.empty()— 빈 Optional 생성
Optional에서 값을 꺼내는 방법
orElse(기본값)Optional<String> box = Optional.ofNullable(null); String result = box.orElse("Guest"); // box가 비었으니 "Guest" System.out.println(result); // Guest //질문 //Optional<String> box = Optional.ofNullable(null); // 비어 있을 수 있는 변수에 null 대신에 저렇게 미리 입력해놓으면 되는 것인가??
orElseGet(함수) — 기본값을 필요할 때만 생성하고 싶을 때Optional<String> box = Optional.of("hi"); String result = box.orElseGet(() -> "Guest"); System.out.println(result); // hi
Optional을 조건문 없이 다루는 메소드들
isPresent()/isEmpty()— true/false로 값의 존재 여부 반환
Optional<String> box = Optional.ofNullable(null); if (box.isPresent()) { System.out.println("값 있음"); } else { System.out.println("값 없음"); }
ifPresent(Consumer)— 값이 있을 때만 실행 (비어 있으면 에러 없이 무시)
Optional<String> box = Optional.of("hi"); box.ifPresent(value -> System.out.println(value)); // hi 출력
orElse(기본값)— 값이 없을 때 기본값 반환
ifPresentOrElse(있을 때, 없을 때)— 값의 유무에 따라 다른 동작 실행
Optional<String> box = Optional.empty(); box.ifPresentOrElse( value -> System.out.println("값: " + value), () -> System.out.println("값 없음") );
map(변환)— 상자 안의 값을 변환해서 새 상자로 반환
Optional<String> box = Optional.of("hello"); Optional<Integer> lengthBox = box.map(s -> s.length()); System.out.println(lengthBox.orElse(0)); // 5 //✅ 한 줄씩 해석: //1. `box` 안에는 "hello"가 있음 //2. `map`이 "hello"를 꺼내서 `s.length()` 실행 → 5 //3. 결과를 `Optional[5]` 로 다시 감쌈 //만약 box가 비어있으면? //- map은 아무것도 안 하고 그대로 empty가 됨 (안전)
filter(조건)— 조건을 만족하면 유지, 아니면 empty로 변환
Optional<String> box = Optional.of("apple"); Optional<String> result = box.filter(s -> s.startsWith("a")); System.out.println(result.orElse("없음")); // apple =============================================================== Optional<String> box = Optional.of("banana"); Optional<String> result = box.filter(s -> s.startsWith("a")); System.out.println(result.orElse("없음")); // 없음
try-catch
try-catch란?
- 실행 중에 발생할 수 있는 에러를 잡아서 프로그램이 죽지 않게 하는 장치
기본 구조
try { // 위험한 코드 } catch (예외타입 e) { // 에러가 났을 때 실행할 코드 } ================================================================= int a = 10; int b = 0; int result = a / b; // 💥 여기서 터짐 System.out.println("끝"); // Exception in thread "main" java.lang.ArithmeticException: / by zero // 에러발생 ================================================================= try { int a = 10; int b = 0; int result = a / b; System.out.println(result); } catch (ArithmeticException e) { System.out.println("0으로 나눌 수 없습니다"); } System.out.println("끝");
Exception (예외)
예외를 클래스로 다루고, 상속으로 체계화
- 에러는 그냥 터지는 게 아니다
- 에러도 객체이고, 타입이며, 설계 대상이다
- 예외는 전부 클래스이고, 상속과 다형성 적용 가능
- 에러를 분류한다
class InvalidAgeException extends RuntimeException {} class NotEnoughMoneyException extends RuntimeException {}
그래서 상속구조로 아래와 같이 에러를 컨트롤하는 것이 목표
RuntimeException └── GameException ├── InvalidActionException ├── NotEnoughGoldException └── ItemNotFoundException
에러를 설계 대상으로 보는 사고방식 훈련
Result 패턴
핵심 아이디어
- 성공과 실패를 예외가 아니라 값으로 표현한다
try { Item item = buyItem("Potion", playerGold); System.out.println("구매 성공"); } catch (ItemNotFoundException e) { System.out.println("아이템이 없습니다"); } catch (NotEnoughGoldException e) { System.out.println("골드가 부족합니다"); }
본질적인 질문
- 골드 부족, 아이템 없음이 정말 예외 상황인가?
- 흔하게 발생하는 정상적인 케이스이며, 잘못된 상태가 아님
- 이걸 굳이 try-catch로 처리해야 할까?
해결 방법
- Result 패턴을 도입해 예외가 아니라 값으로 반환한다
❓ 이해 안 된 부분 / 도움 요청
try-catch나 Optional을 사용한다는 것은 이미 에러 발생 시점을 알고 있다는 뜻 아닌가? 그렇다면 컴파일 단계에서 에러가 발생하지 않도록 처리하는 것이 더 나은 방향 아닌가?
=> 외부 데이터나 사용자 입력을 받을 때는 예외를 예측하기 어려운 경우가 많아서 주로 사용한다.한다.

