## 자바 `Optional` 주요 메서드 정리 | 메서드 | 설명 | |-----|-----| | `of(T value)` | `null`이 아닌 값을 감싸는 `Optional` 생성 | | `ofNullable(T value)` | `null`일 수도 있는 값을 감싸는 `Optional` 생성 | | `empty()` | 비어 있는 `Optional` 생성 | | `isPresent()` | 값이 존재하면 `true`, 없으면 `false` 반환 | | `isEmpty()` | 값이 없으면 `true`, 있으면 `false` 반환 | | `get()` | 값이 존재하면 반환, 없으면 `NoSuchElementException` 발생 | | `orElse(T other)` | 값이 존재하면 반환, 없으면 기본값 반환 | | `orElseGet(Supplier)` | 값이 존재하면 반환, 없으면 함수 실행 결과 반환 | | `orElseThrow()` | 값이 존재하면 반환, 없으면 예외 발생 | | `or(Supplier)` | 값이 존재하면 현재 `Optional` 반환, 없으면 다른 `Optional` 반환 | | `ifPresent(Consumer)` | 값이 존재하면 실행할 코드 지정 | | `ifPresentOrElse(Consumer, Runnable)` | 값이 존재하면 실행할 코드, 없으면 실행할 코드 지정 | | `map(Function)` | 값을 변환하여 새로운 `Optional` 반환 | | `flatMap(Function)` | 중첩된 `Optional`을 평탄화하여 반환 | | `filter(Predicate)` | 조건을 만족하면 `Optional` 유지, 아니면 비움 | --- ## 자바 `Optional` 쉽게 설명하기 ### `Optional`이란? 자바에서는 `null`이 자주 등장한다. 하지만 `null`을 잘못 다루면 `NullPointerException`(NPE)이 발생한다. 이 문제를 해결하기 위해 나온 것이 **`Optional`(옵셔널)**이다. > **"옵셔널은 값이 있을 수도 있고 없을 수도 있는 박스다."** 즉, **값을 안전하게 감싸고 다룰 수 있도록 도와주는 도구**다. 값이 있으면 꺼내서 사용하고, 없으면 `null` 대신 기본값을 사용하거나 예외를 발생시킬 수 있다. --- ### `Optional` 사용 예제 #### 1. `Optional` 생성하기 ```java Optional name = Optional.of("Alice"); // 값이 있는 Optional Optional emptyName = Optional.empty(); // 비어 있는 Optional Optional nullableName = Optional.ofNullable(null); // null 가능 ``` - `Optional.of(value)`: `null`이 아닌 값을 감쌈 (null이면 예외 발생) - `Optional.empty()`: 비어 있는 `Optional` 생성 - `Optional.ofNullable(value)`: `null`일 수도 있는 값을 감쌈 --- #### 2. 값이 있는지 확인하기 ```java Optional name = Optional.of("Alice"); System.out.println(name.isPresent()); // true System.out.println(name.isEmpty()); // false ``` - `isPresent()`: 값이 있으면 `true` - `isEmpty()`: 값이 없으면 `true` --- #### 3. 값 가져오기 ```java Optional name = Optional.of("Alice"); System.out.println(name.get()); // "Alice" ``` 하지만 **값이 없을 때 `get()`을 호출하면 예외가 발생**하므로 주의해야 한다. ```java Optional emptyName = Optional.empty(); System.out.println(emptyName.get()); // NoSuchElementException 발생! ``` 그래서 **`orElse()` 또는 `orElseGet()`을 사용하는 것이 안전하다.** ```java Optional emptyName = Optional.empty(); String result1 = emptyName.orElse("Unknown"); // 기본값 제공 String result2 = emptyName.orElseGet(() -> "Generated Name"); // 함수로 기본값 제공 System.out.println(result1); // "Unknown" System.out.println(result2); // "Generated Name" ``` --- #### 4. 값이 없을 때 예외 던지기 ```java Optional emptyName = Optional.empty(); String name = emptyName.orElseThrow(() -> new IllegalArgumentException("이름이 없습니다!")); ``` 값이 없으면 `IllegalArgumentException`을 던진다. --- #### 5. 값이 있을 때만 실행하기 (`ifPresent`) ```java Optional name = Optional.of("Alice"); name.ifPresent(n -> System.out.println("이름: " + n)); // 이름이 있으면 출력 ``` 값이 없으면 아무 일도 일어나지 않는다. --- #### 6. 값이 있으면 실행, 없으면 다른 작업 수행 (`ifPresentOrElse`) ```java Optional name = Optional.empty(); name.ifPresentOrElse( n -> System.out.println("이름: " + n), // 값이 있을 때 실행 () -> System.out.println("이름이 없습니다!") // 값이 없을 때 실행 ); ``` --- #### 7. 값 변환하기 (`map`) ```java Optional name = Optional.of("Alice"); Optional length = name.map(String::length); System.out.println(length.get()); // 5 ``` - `map(Function)`: 값이 있으면 변환하고, 없으면 `Optional.empty()` 유지 --- #### 8. 중첩된 `Optional`을 평탄화 (`flatMap`) ```java Optional> nested = Optional.of(Optional.of("Alice")); Optional flat = nested.flatMap(n -> n); System.out.println(flat.get()); // "Alice" ``` - `flatMap(Function)`: 중첩된 `Optional`을 단일 `Optional`로 변환 --- #### 9. 조건에 맞는 값만 유지하기 (`filter`) ```java Optional name = Optional.of("Alice"); Optional filtered = name.filter(n -> n.startsWith("A")); System.out.println(filtered.get()); // "Alice" ``` - `filter(Predicate)`: 조건을 만족하면 `Optional` 유지, 아니면 `Optional.empty()` 반환 --- ### `Optional`을 사용하면 좋은 이유 1. **`null` 체크가 필요 없음** → `if (value != null)` 같은 코드 제거 가능 2. **코드가 더 읽기 쉬움** → `Optional` 메서드를 통해 명확한 의도를 전달 3. **안전한 값 처리 가능** → `orElse()`, `ifPresent()` 등을 활용하여 `null`을 안전하게 대체 즉, **"옵셔널은 값이 있을 수도 있고 없을 수도 있는 안전한 박스"**다. 무작정 `null`을 다루는 것보다 `Optional`을 활용하면 **예외 없이 더 깔끔하고 안전한 코드**를 작성할 수 있다.