[Java] Optional이란

·2025년 6월 14일
0

Java

목록 보기
1/13

💡Optional이란

Optional은 Java8에서 도입된 null 처리의 대안 클래스로, 값이 있을 수도 있고 없을 수도 있음을 명시적으로 표현하기 위해 사용된다. null을 직접 다루는 것보다 안전하고 명확한 코드 작성을 도와준다.


✅Optional이 필요한 이유

기존 자바에서는 null 체크하는 로직을 포함하는 코드가 자주 나왔다.

String name = getUserName();
if (name != null) {
    System.out.println(name.length());
}

null 체크를 해야할 부분이 많다면 코드가 복잡해져 가독성이 떨어지고, 실수로 null 체크를 누락하면 NullPointerException이 발생한다.

➡️이를 방지하기 위해 Optional이 등장했다.


✅Optional 기본 구조

public final class Optional<T> {
    private final T value;
    ...
}
  • Optional<T>는 내부에 T타입의 객체를 하나 감싼다.
  • value가 null일 수도 있고, null이 아닐 수도 있는 객체를 감싸고 있는 Wrapper클래스다.

✅Optional의 주요 메서드

메서드설명
Optional.of(value) 주어진 값으로 Optional 객체를 생성
단, value가 null이 아닌 경우에 사용
Optional.ofNullable(value)주어진 값으로 Optional 객체를 생성
단, value의 값이 null인 경우 Optional.empty()를 반환
Optional.empty() 빈(empty) Optional 객체를 반환
값이 없음을 나타내는 경우에 사용
isPresent()Optional 객체에 값이 존재하는지 여부 확인
값이 존재하면 true, 값이 없으면 false 반환
isEmpty() Optional 객체에 값이 없는지 확인
!Optional.isPresent() 와 같음
ifPresent(Consumer)값이 존재하면 동작 수행
orElse(default) 값이 존재하는 경우 해당 값을 반환하고,
값이 없는 경우 주어진 기본 값을 반환
값이 존재 여부에 상관없이 항상 실행된다.
orElseGet(Supplier) 값이 존재하는 경우 해당 값을 반환하고,
값이 없는 경우 주어진 Supplier로부터 기본 값을 가져옴. 
값이 존재하지 않은 경우에만 실행된다.
orElseThrow() 값이 존재하는 경우 해당 값을 반환하고,
값이 없는 경우에는 예외 발생 시킴
map(Function) 값이 존재하는 경우에 주어진 Function에 따른
결과 값으로 새로운 Optional을 반환
filter(Predicate<T>)값이 존재하고, Predicate을 만족하는 경우에만 값을 반환

1. Optional.of(value)

주어진 값으로 Optional객체를 생성한다. 주의할 점은 value값이 절대 null이 아닌 경우에만 사용되는 메서드이다. value값이 null인 경우 NullPointerException이 발생하게 된다.

📍사용예시

Optional<String> name = Optional.of("자바");
System.out.println(name); // 출력: Optional[자바]
  • vaulue가 null이면 NullPointerException 발생
Optional<String> name = Optional.of(null); // 예외 발생

2. Optional.ofNullable(value)

주어진 값으로 Optional 객체를 생성한다. Optional.of(value)와 달리 value값이 null 일 수도 있는 경우에 사용하는 메서드이다. value가 null인 경우 Optional.empty()를 반환한다.

📍사용예시

Optional<String> name = Optional.ofNullable("자바");
System.out.println(name); // 출력: Optional[자바]

Optional<String> none = Optional.ofNullable(null);
System.out.println(none); // null인 경우 출력: Optional.empty

3. Optional.empty()

 값이 없음을 나타내는 빈(empty) Optional 객체를 반환한다. 

📍사용예시

Optional<String> empty = Optional.empty();
System.out.println(empty); // 출력: Optional.empty

4. isPresent(), isEmpty()

Optional 객체에 값이 존재하는 지 여부를 확인할 때 사용하는 메서드
isPresent()값이 존재하면 true, 값이 없으면 flase를 반환
isEmpty()값이 존재하지 않으면 true, 값이 존재하면 false 반환

📍사용예시

Optional<String> name = Optional.of("자바");

if (name.isPresent()) {	//값이 존재하면 true
    System.out.println("값이 존재합니다.");
}

if(name.isEmpty()) { //값이 존재하지 않으면 true
	System.out.println("값이 존재하지 않는다.");
}

5. ifPresent(Consumer)

Optional 객체에 값이 존재하는 경우에만 주어진 Consumer를 수행한다. 즉, 값이 있으면 동작이 실행되고, 값이 없으면 동작을 수행하지 않는다.

📍사용예시

Optional<String> name = Optional.of("자바");
// 값이 존재하므로 ifPresent 동작 실행.
name.ifPresent(n -> System.out.println("이름 -> " + n));  
// 출력 : 이름 -> 자바
Optional<String> nullName = Optional.ofNullable(null);
//값이 null이므로 ifPresent 동작 실행하지 않음
nullName.ifPresent(n -> System.out.println("이름 -> " + n));  

6. orElse(default)

 Optional에 값이 존재하는 경우에는 해당 값을 반환하고, 값이 없는 경우에는 주어진 기본 값을 반환한다. 주의할 점은 Optional에 값이 존재하는 경우에도 orElse()가 실행되어 기본값을 무조건 생성한다. 따라서 비용이 큰 기본값을 얻을 때 사용하기 보다 단순한 기본 값을 얻고자 할 때 사용하는 것이 일반적이다.

📍사용예시

Optional<String> name = Optional.of("자바");
String result = name.orElse("기본값");
System.out.println(result); // 출력: 자바

7. orElseGet(Supplier)

Optional에 값이 존재하는 경우에는 해당 값을 반환하고, 값이 없는 경우에는 주어진 Supplier로부터 기본 값을 가져온다. orElse()와는 달리 Optional에 값이 없는 경우에만 Supplier가 호출되어 기본값을 생성한다.

📍사용예시

String value = Optional.ofNullable(null).orElseGet(() -> "기본값");
System.out.println(value); // 출력: 기본값

8. orElseThrow()

 Optional에 값이 존재하는 경우에는 해당 값을 반환하고, 값이 없는 경우에는 예외를 발생

📍사용예시

String value = Optional.ofNullable(null)
    .orElseThrow(() -> new IllegalArgumentException("값이 없습니다"));
  • Optional 객체가 null이므로 IllegalArgumentException 예외 발생

9. map(Function<T, R>)

 Optional 객체에 값이 존재하는 경우에 주어진 Function에 따른 결과 값으로 새로운 Optional을 반환

📍사용예시

Optional<String> name = Optional.of("자바");

Optional<Integer> nameLength = name.map(String::length);
System.out.println(nameLength); // 출력: Optional[2]
  • name안에 있는 값이 존재할 경우만 그 값을 꺼내서 String::length 함수를 적용( "자바" -> 2)
  • 그 2를 다시 Optional로 감싸서 nameLength가 됨.
  • 값을 변환하여 새로운 Optinal로 반환

10. filter(Predicate)

 Optional 객체에 값이 존재하고, 주어진 Predicate을 만족하는 경우에 기존 Optional을 반환합니다. 그렇지 않은 경우에는 Optional.empty()를 반환합니다.

📍사용예시

//조건을 만족하지 못하는 코드
Optional<String> name = Optional.of("자바");
Optional<String> filtered = name.filter(n -> n.length() > 2);
System.out.println(filtered); // 출력: Optional.empty

위 코드에서는 Optional 안에 들어있는 값(자바)가 **조건을 만족하는지 검사하고 조건을 만족하면 값을 그대로 유지하고, 만족하지 않으면 Optional.empty()를 리턴

  • name은 "자바"를 감싸고 있음.
  • filter의 조건(n.length() > 2) -> 문자열의 길이가 2보다 크다.를 충족해야함
  • "자바"의 길이는 2 -> 조건 만족하지 않음
  • 출력 결과는 Optional.empty
//조건을 만족하는 코드
Optional<String> name = Optional.of("스프링");
Optional<String> filtered = name.filter(n -> n.length() > 2);
System.out.println(filtered); // 출력: Optional.empty
  • name이 필터의 조건 (n.length() > 2)을 충족하므로 출력 결과는 Optional[스프링]

✅ Optional 사용 시 주의사항

1. 리턴값으로만 쓰기를 권장

➡️메소드의 매개변수 타입, 맵의 키 타입, 인스턴스 필드 타입으로 사용하지 않는 것이 좋다.

// ❌권장되지 않음 : 매개변수 타입으로 사용
public void process(Optional<String> input) {
	...  
}
  
// ⭕권장됨
public void process {
	...  
}  

2. Optional을 리턴하는 메소드에서 null을 리턴하지 말 것

➡️Optional을 반환하는 메소드에서 절대로 null을 반환하지 않도록 한다.

// ❌권장되지 않음 : null 리턴
public Optional<String> getVlaue() {
	return null; 
}

// ⭕권장됨  
public Optional<String> getVlaue() {
	return Optional.ofNullable(null); 	//null일 경우 빈 Optional을 반환
}  

3. Optional.get() 직접 사용 지양할 것

➡️Optional.get()을 직접 사용하면 값이 없을 때 예외가 발생하므로 직접 사용을 지양한다.

// ❌권장되지 않음
Optional<String> name = Optional.empty();
String value = name.get();  // NoSuchElementException 발생

// ⭕권장됨  
Optional<String> name = Optional.of("자바");
String value = name.orElse("기본값");  // 값이 있으면 그대로, 없으면 기본값
System.out.println(value); // 출력: 자바

4. Collection, Map, Stream, Array, Optional을 Optional로 감싸지 말 것

➡️Collection, Map, Stream, Array, Optional을 다시 Optional로 감싸지 않도록 한다.

// ❌권장되지 않음
public Optional<Optional<String>> getOptionalValue() {
	Optional<String> value = Option.of("test");
  	return Optional.of(value); 	//중첩 사용 ❌
}

// ⭕권장됨  
public Optiona<String> getOptionalValue() {
  	return Optional.of(value); 
}
profile
배우고 기록하며 성장하는 백엔드 개발자입니다!

0개의 댓글