Optional에 대해

iy·2024년 2월 20일

Java

목록 보기
8/8

Optional<T>

  • T 타입 객체의 래퍼 클래스 - Optioanal<T>
//래퍼클래스 : Integer, Long을 가지고 있는 클래스
public final class Optional<T> {
	private final T value; // T 타입의 참조변수
    // 모든 종류의 객체 저장 가능
	// null도 저장 가능 
}

null이 저장 가능할 때 장점

  1. null을 직접 다루는 것은 위험
  • NullPointerException발생 방지
  1. null 체크하는 if문을 작성하지 않아 코드가 보다 간단해짐
Object result = getResult();

이 메서드의 반환값은 null이거나 객체 일텐데

result.toString(); // 반환값이 null일 때 nullPointerException발생

이를 방지하기 위해선

if(result != null){
	println(result.toString());
}

이렇게 확인해줘야 함

result에 null을 직접 담아줬던 것을 Optional 사용으로 null을 Optional 객체에 null주소를 담아주게 됨
Optional로 감싸주면 해당 result는 null이 아니게 되므로 위에 반환값이 null일 때 있었던 문제들(NullPointerException, if문으로 null제어) 방지가 가능함

Optional<T> 객체 생성하기

String str = "abc";
Optional<String> optVal = Optional.of(str); 
Optional<String> optVal = Optional.of(null); // NullPointerException 발생 -> null자체를 of메서드로 저장 불가능
Optional<String> optVal = Optional.ofNullable(null); // ok -> ofNullable로 null값 저장 가능
  • str : 0x100 -> "abc"
    - 이때 0x100이 null이 될 수 있음
  • optVal : 0x200 -> Optional 객체 : 0x100 -> "abc"
    - Optional객체로 한 단계 더 거치게 하면 0x100은 null이 될 수 있지만 0x200은 null을 절대 갖지 않게 됨

null 대신 Optional<T> 객체를 사용하도록 하자

Optional<String> optVal = null; // 널로 초기화, 바람직하지 않음
Optional<String> optVal = Optional.<String>empty(); // 빈 객체로 초기화
// null로 초기화가 가능은 하지만 빈 Optional 객체로 초기화 하는 것을 권장함-> null 사용을 최소화하기

Optional<T> 객체 값 가져오기

  • get(), orElse(), orElseGet(), orElseThrow()
Optional<String> optVal = Optional.of("abc");
String str1 = optVal.get(); // optVal에 저장된 값을 반환. null이면 예외 발생
String str2 = optVal.orElse(""); // optVal에 저장된 값이 null일 땐 ""을 반환
String str3 = optVal.orElseGet(String::new); //람다식 사용가능 () -> new String();
String str4 = optVal.orElseThrow(NullpointerException::new); //널이면 예외 발생
T orElseGet(Spplier<? extends T> other) // 예외종류 지정 가능
T orElseThrow(Supplier<? extends X> exceptionSupplier)
  • isPresent()-Optional객체의 값이 null이면 false, 아니면 true를 반환
if(Optional.ofNullable(str).isPresent()) { // if(str != null) {
	System.out.println(str);
}
// ifPrensent() : 널이 아닐 때만 작업 수행, 널이면 아무 일도 안 함
// Optional.ofNullable(str).ifPresent(System.out::println);

OptionalInt, OptionalLong, OptionalDouble

  • 성능 향상을 위해 사용
  • 기본형을 감싸는 래퍼클래스
public final class OptionalInt {
	```
    private final boolean isPresent; // 값이 저장되어 있으면 true
    private final int value; // int 타입의 변수
}
  • OptionalInt의 값 가져오기 - int getAsInt()
Optional 클래스값을 반환하는 메서드
Optional<T>T get()
OptionalIntint getAsInt()
OptionalLonglong getAsLong()
OptionalDoubledouble getAsDouble()
  • 빈 Optional객체와의 비교
OptionalInt opt = OptionalInt.of(0); // OptionalInt에 0을 저장
OptionalInt opt2 = OptionalInt.empty(); // OptionalInt에 0을 저장 : 아무것도 저장하지 않지만 기본값이 0이므로 0을 저장

두 값 모두 0을 저장하는데 구분이 가능한가? - isPresent로 확인해보자

System.out.println(opt.isPresent());  // true
System.out.println(opt2.isPresent());  // false
System.out.println(opt.equals(opt2));  // false

각 값을 isPresent() 메서드로 비교해보면 0을 직접 저장한 opt값은 값이 존재하므로 true를 반환하고 빈 값을 저장한 opt2는 isPresent()가 false를 반환하므로 값이 존재하지 않는다는 것을 확인할 수 있다.
opt와 opt2의 값이 둘 다 0을 저장해 같은 값이라 볼 수 있지만 사실 둘은 같다고 볼 수 없다!


🐾
오늘 학습 중에 Optional을 사용하는 이유를 생각해보자 하셔서 추가적으로 학습하고 정리해봤다.
null을 다루기에 좋다는 것만 알았는데 강의를 듣고 정리해보니 null을 직접 다루지 않아서 좋다는 점을 좀 더 자세하게 이해할 수 있었다.

		String username = requestDto.getUsername();
		Optional<User> checkUsername = userRepository.findByUsername(username);
        if(checkUsername.isPresent()){
            throw new IllegalArgumentException("중복된 아이디가 존재합니다.");
        }

내가 과제할 때 작성했던 코드다.
username은 요청값으로 사용자가 입력하는 값이다.
이 입력값으로 repository에서 findByUsername으로 해당 값을 찾아 checkUsername에 담아준다. 이때 사용자가 입력한 값이 없을 수 있다. 즉 null 값이 checkUsername에 담길 수 있었다.
Optional로 해당 값을 감싸서 null값이어도 exception 발생을 피할 수 있었고 나아가 isPresent() 를 이용해서 원하는 중복체크 코드를 작성할 수 있었다.

자바의 정석 Optional강의

0개의 댓글