티스토리 뷰

 

사용자의 입력은 믿을 수 없는 정보이다.

사용자 입력에서 발생할 수 있는 예외 케이스를 고민해야 한다. 그리고 예외 케이스에 대한 이 필요하다.

ex) 이메일 입력창에 특수 문자를 입력할 수 있다.

 

null을 대하는 자세

→ 항상 NPE를 방지하는 방향으로 경각심을 가지고 코드를 작성한다.

return null을 자제한다. NPE 발생 여지를 만든다.

→ 대안책으로 Optional이 있다.

 

Optional에 대하여

→ Optional은 비싼 객체다. 꼭 필요한 상황에서만 반환 타입으로만 사용한다. 반환 타입이 아닌 파라미터로 받지 말자.

→ Optional은 분기 케이스가 존재한다.

  • Optional 자체가 null인지
  • Optional에 담긴 데이터가 null인지

따라서 파라미터Optional을 받아서는 안 된다. Optional의 분기 케이스를 확인해야 하므로 안티 패턴이 된다.

→ Optional을 받았다면 최대한 빠르게 해소하여 분기 케이스를 만들지 말자.

 

Optional을 해소하는 방법

  • 분기문을 만드는 ifPresent(), get() 대신 풍부한 API를 사용한다.
    • ex) orElseGet(), orElseThorw(), ifPresent(), ifPresentOrElse()
  • orElse(), orElseGet()의 차이를 숙지한다. 무분별한 사용은 성능에 영향을 미친다.
    • orElse() : 파라미터로 넘어온 값이 항상 사용된다. → Optional에 담긴 데이터가 무거운 작업이라면 성능에 영향을 미친다. 왜냐하면 Optional에 담긴 데이터가 null이 아니더라도 작업을 반드시 실행하기 때문이다.
    • orElseGet() : Supplier를 받고 Optional에 담긴 데이터가 null인 경우에만 Supplier가 사용된다. 따라서 Optional에 데이터가 담겨있다면, 불필요하게 Supplier를 실행하지 않는다.
public T orElse(T other) {
	return value != null ? value : other;
}

public T orElseGet(Supplier<? extends T> supplier) {
	return value != null ? value : supplier.get();
}
somethingOptional.orElse(performanceHeavy()); // performanceHeavy() 항상 실행
somethingOptional.orElseGet(() -> performanceHeavy()); // Optional에 담긴 데이터가 null인 경우에만 실행

 

Optional.orElse() → 안티 패턴

orElse()는 Optional에 담긴 데이터와 상관없이 항상 파라미터로 전달받은 값을 사용한다.

public T orElse(T other) {
        return this.value != null ? this.value : other;
}
  • emptyObjectnotEmptyObject 둘 다 orElse()가 호출되면서 performanceHeavy()가 호출된다. notEmptyObject는 불필요한 계산을 하는 것이기 때문에 안티 패턴이 된다.
import java.util.Optional;

public class Main {

    private static final int JOB_COUNT = 100_000_000;

    public static void main(String[] args) {
        System.out.println(">>> emptyObject");
        Optional<Integer> emptyObject = Optional.empty();
        Integer result1 = emptyObject.orElse(performanceHeavy());
        System.out.println(">>> emptyObject = " + emptyObject);
        System.out.println(">>> result1 = " + result1 + "\\n");

        System.out.println(">>> notEmptyObject");
        Optional<Integer> notEmptyObject = Optional.of(10);
        Integer result2 = notEmptyObject.orElse(performanceHeavy());
        System.out.println(">>> notEmptyObject = " + notEmptyObject);
        System.out.println(">>> result2 = " + result2 + "\\n");
    }

    private static int performanceHeavy() {
        System.out.println(">>> performanceHeavy() 호출");
        int count = 0;
        for (int i = 0; i < JOB_COUNT; i++) {
            count++;
        }
        return count;
    }
}

 

notEmptyObjectperformanceHeavy()를 호출하였으나, 해당 메서드에 계산된 값을 사용하지 않는다.

 

Optional.orElseGet() → Optional.orElse() 대안책

orElseGet()은 Optional에 담긴 데이터가 null이 아니라면 파라미터로 받은 Supplier를 사용하지 않는다.

@ValueBased
public final class Optional<T> {
    public T orElseGet(Supplier<? extends T> supplier) {
        return this.value != null ? this.value : supplier.get();
    }
}
  • emptyObject의 경우 Optional에 null 데이터가 담겨있기 때문에 performanceHeavy()를 호출한다.
    • performanceHeavy()가 호출되면서 result1에는 100_000_000이 담긴다.
  • notEmptyObject의 경우 Optional에 10이라는 데이터가 담겨있기 때문에 performanceHeavy() 를 호출하지 않는다.
    • performanceHeavy()가 호출되지 않기 때문에 result2에는 10이 담긴다.
import java.util.Optional;

public class Main {

    private static final int JOB_COUNT = 100_000_000;

    public static void main(String[] args) {
        System.out.println(">>> emptyObject");
        Optional<Integer> emptyObject = Optional.empty();
        Integer result1 = emptyObject.orElseGet(() -> performanceHeavy());
        System.out.println(">>> emptyObject = " + emptyObject);
        System.out.println(">>> result1 = " + result1 + "\\n");

        System.out.println(">>> notEmptyObject");
        Optional<Integer> notEmptyObject = Optional.of(10);
        Integer result2 = notEmptyObject.orElseGet(() -> performanceHeavy());
        System.out.println(">>> notEmptyObject = " + notEmptyObject);
        System.out.println(">>> result2 = " + result2);
    }

    private static int performanceHeavy() {
        System.out.println(">>> performanceHeavy() 호출");
        int count = 0;
        for (int i = 0; i < JOB_COUNT; i++) {
            count++;
        }
        return count;
    }
}

 

notEmptyObject는 10이라는 데이터를 가지고 있기 때문에 불필요하게 performanceHeavy()를 호출하지 않는다.

 

 

Total
Today
Yesterday
최근에 올라온 글
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30