ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] Optional
    언어/Java 2021. 3. 14. 22:52

    Optional 클래스는 객체를 포장해주는 래퍼 클래스로 모든 타입의 참조 변수를 담을 수 있습니다. Optional 객체를 사용하면 복잡한 조건문 없이 NullPointerException (;NPE) 예외 처리를 할 수 있습니다.

    생성

    Optional 객체 생성은 .empty(), .of(), .ofNullable() 이 있습니다.

    .of() 메소드를 사용해서 객체를 생성할 때, 인자값으로 null이 전달된다면 NPE가 발생하므로 null이 입력될 수도 있다면 안전하게 ofNullable() 메소드를 호출하는 것이 좋습니다.

    Optional<String> op1 = Optional.empty(); // Optional.empty - null을 담고 있는 빈 객체
    Optional<String> op2 = Optional.ofNullable(null); // Optional.empty - null을 담고 있는 빈 객체
    Optional<String> op3 = Optional.ofNullable("aaa"); // Optional[aaa]
    Optional<String> op4 = Optional.of("aaa"); // Optional[aaa]

    접근

    get()

    .get() 메소드는 조회하고자 하는 값이 존재하면 해당 값을 반환하고 그렇지 않으면 NoSuchElementException을 발생시킵니다. 이러한 예외처리를 위해 .isPresent() 메소드로 검사를 하는 것이 좋습니다.

    .orElse("대체값") 메소드는 값이 존재하지 않으면 입력된 대체값을 반환합니다.

    .orElseGet(람다식) 메소드는 값이 존재하지 않으면 람다의 결과를 반환합니다.

    .orElseThrow(예외) 메소드는 값이 존재하지 않으면 입력된 예외를 발생시킵니다.

    레퍼런스 타입이 아닌 사용자가 만든 객체의 유무를 확인할 땐 .orElse()보단 .orElseGet()이 더 효율적입니다. .orElse(대체값) 메소드는 optional에 값의 유무와 상관없이 대체값이 먼저 생성됩니다. 반면 .OrElseGet()은 optional에 값이 없을때만 입력된 람다식을 호출합니다.

    Optional<String> op1 = Optional.empty();
    if (op1.isPresent()) { // 값이 존재하는지 검사. 있으면 true
        System.out.println(op1.get());
    }
    
    System.out.println(op1.orElse("bbbbb")); // bbbbb 반환
    System.out.println(op1.orElseGet(String::new)); // new String() 반환
    System.out.println(op1.orElseThrow(RuntimeException::new)); // RuntimeException 발생
    
    Optional<Button> op = Optional.empty();
    
    op.orElse(new Button()); // 이거보단
    op.orElseGet(Button::new); // 이거로

    .ifPresent()

    위에서 .isPresent() 메소드는 값의 여부를 검사하고 boolean 타입으로 값을 반환하는데에 반해 ifPresent()는 값을 반환하는 대신 함수형 인자로 전달된 로직을 실행시킵니다. 인자는 람다나 메소드 레퍼런스가 될 수 있습니다.

    Optional<String> op1 = Optional.ofNullable(null);
    op1.ifPresent(
            temp -> { System.out.println("값 존재"); }
    ); // 실행 X
    
    Optional<String> op2 = Optional.ofNullable("AAA");
    op2.ifPresent(
            temp -> { System.out.println("값 존재"); }
    ); // 실행 O

    변환

    .map()

    map()을 사용해 추출할 때, 내부 데이터를 변환한 다음 추출할 수 있습니다.

    Optional<String> op1 = Optional.of("abcde");
    System.out.println(op1.map(String::toUpperCase)); // Optional[ABCDE]
    System.out.println(op1); // Optional[abcde]

    .filter()

    .filter()를 사용해 조건식에 맞는지 검증을 할 수 있습니다.

    op1.filter(name -> name.equals("ab"));

    map() 과 filter() 메소드를 사용해 아래와 같은 기존 로직을 변경할 수 있습니다.

    public SmartPhone getSmartPhone(Button button) {
        if (button != null && button.type.equals("AOS")) {
            return button.getSmartPhone();
        }
    }
    
    // 아래와 같이 변경 가능
    
    public Optional<SmartPhone> getSmartPhone(Button button) {
        return Optional.ofNullable(button)
                .filter(b -> b.type.equals("AOS"))
                .map(Button::getSmartPhone);
    }

    댓글