프로그래밍 언어/자바(JAVA)

자바(JAVA) - Optional

나아가는중 2022. 1. 21. 21:59
반응형

Optional은 jdk 1.8(java 8)부터 추가된 기능입니다.

 

 

Optional 클래스는 제네릭 타입의 클래스이며 타입 파라미터로 T 타입을 사용되며 T 타입의 참조 변수 value가 있습니다.

public final class Optional<T> {
    private final T value;
    
    ...
}

 

제네릭 타입은 데이터 형식에 의존하지 않고, 모든 데이터 타입을 갖도록 하는 방법입니다. 클래스에서 미리 타입을 지정하지 않고 사용자에 의해 지정됩니다.

 

제네릭을 사용하게 되면 컴파일 타임에 강한 타입 체크가 가능하며, 외부에서 타입을 지정하여 캐스트가 불필요한 장점 등이 있습니다.

 

성능 향상을 위해 기본타입은 OptionalInt, OptionalDouble과 같은 래퍼 클래스들을 사용하는 것이 좋습니다.

public final class OptionalInt {
    private final boolean isPresent;
    private final int value;

    private OptionalInt() {
        this.isPresent = false;
        this.value = 0;
    }
    
    ...
}

OptionalInt의 예시로 보면 변수 value는 T가 아닌 int형으로 되어있습니다.

람다와 스트림으로 모든 것을 감싸고 있고 객체로 다루기 때문에 Optional <T>의 경우 성능이 좋지 않습니다.

 

 

Optional을 사용하는 이유

1. 간접적으로 null을 다루기 위해 사용됩니다. null을 직접적으로 다르는 것은 NullPointException 오류가 발생할 수 있어 위험합니다.

2. null 체크가 필요없습니다. null 체크를 위해 if문을 사용하지 않아도 됩니다.

 

변수의 값을 Optional 객체 안에 저장하여 NullPointerException 오류가 발생하지 않으며 null을 체크할 필요가 없습니다. Optional 객체의 value가 null이라도 변수는 Optional 객체의 주소를 갖고 있으므로 값이 null이 아니게 됩니다.

 

 

Optional 객체 생성

Optional 객체 생성은 주로 Optional 클래스의 of() 메서드를 사용합니다.

 public static <T> Optional<T> of(T value) {
     return new Optional<>(value);
 }

이 of() 메서드는 Optional 클래스의 생성자 Optional(T value)를 호출합니다.

private Optional(T value) {
    this.value = Objects.requireNonNull(value);
}

생성자에서는 requireNonNull() 메서드를 호출합니다.

public static <T> T requireNonNull(T obj) {
    if (obj == null)
        throw new NullPointerException();
    return obj;
}

여기에서 매개변수가 null인지 검사하여 null인 경우 NullPointerException을 throw 해줍니다.

null이 아니라면 매개변수를 return 해주고 생성자에서 value에 매개변수를 저장합니다.

 

만약 null을 저장하고 싶은 경우에는 of() 메서드 대신 ofNullable() 메서드를 사용해주면 됩니다.

public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}

null인지 검사하여 null인 경우 empty() 메서드를 호출합니다.

public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}

EMPTY는 Optional의 기본 생성자입니다. 기본 생성자로 생성된 Optional 객체를 리턴해줍니다.

private static final Optional<?> EMPTY = new Optional<>();

기본 생성자는 value 값에 null을 저장합니다.

private Optional() {
    this.value = null;
}

 

이렇게 생성된 Optional 객체는 null을 저장할 수 있으며, NullPointException 오류를 발생시키지 않습니다.

public class MyOptional {
    public static void main(String[] args) {

        Optional<Integer> t  = Optional.ofNullable(null);
        System.out.println(t); // 출력결과: Optional.empty
    }
}

 

ofNullable(null) 매서드로 생성된 결과가 Optional.empty를 보면, null을 저장할 때 빈 객체로 초기화하며 null인 경우 ofNullable에서 empty() 메서드를 호출하는 것을 알 수 있습니다.

Optional 사용할 때는 null로 초기화하는 대신 empty() 메서드를 사용하여 빈 Optional 객체를 사용하는 것이 좋습니다.

public class MyOptional {
    public static void main(String[] args) {

        Optional<Integer> t  = Optional.empty();
        System.out.println(t); // 출력결과: Optional.empty
    }
}

 

 

 

Optional 주요 함수

orElse() : 저장된 값이 null일 때는 () 안의 값을 반환, null이 아니면 저장된 값을 반환.

public T orElse(T other) {
    return value != null ? value : other;
}

 

orElseGet(): 저장된 값이 null일 때는 ()안의 supplier를 반환.

public T orElseGet(Supplier<? extends T> supplier) {
    return value != null ? value : supplier.get();
}

사용 예시입니다.

import java.util.Optional;
import java.util.function.Supplier;

public class MyOptional {
    public static void main(String[] args) {

        Optional<String> optStr  = Optional.empty();
        
        // 익명 객체 사용
        String str1 = optStr.orElseGet(new Supplier<String>() { // 방법 1
            @Override
            public String get() {
                return new String();
            }
        });

		// 람다식 사용
        String str2 = optStr.orElseGet(() -> new String()); // 방법 2

        String str = optStr.orElseGet(String::new); // 방법 3
    }
}

 

isPresent() : 저장된 값이 null일 때는 false, 아닐 때는 true를 반환.

public boolean isPresent() {
    return value != null;
}

ifPresent() : 저장된 값이 null이 아닐때 () 안의 작업 수행

public void ifPresent(Consumer<? super T> action) {
    if (value != null) {
        action.accept(value);
    }
}

 

반응형