본문 바로가기
Java | spring/Java Basic

Optional 제대로 알기, 면접 대비! (+간단 실무 코드 예시)

by 워니 wony 2021. 6. 3.

프로그래밍을 하다보면 null 처리를 필수적으로 하게 된다. 기존에는 null 체크를 해서 Null 아닌 경우 뒤의 로직으로 넘어가게 분기처리를 하는 형태로 작업을 하게 된다. 이러한 null 처리하기 위해 자바 8 이후 부터는 옵셔널 Optional 사용한다.

 

옵셔널을 상세하게는 아니여도 다른 사람의 코드를 보면서 이런식으로 쓴다고는 알고는 있지만, 남에게 설명할 정도는 아니라면 면접 대비를 한다 생각하고, 옵셔널에 대해 상세하게 알아보도록 하자. 신입 개발자가 optional 제대로 쓰고 알고 있다면 괜찮아 보인다는 선임의 이야기가 있었다. ( 사람마다 다를 있지만) 나도 기회에 제대로 알아봐야지

 

참고로 Optional 사용하기 위해서는 자바 버전 8 이상을 사용하고 있어야 한다. 이유는 아래와 같다.

기존에 런타임 시 NPE(NullPointerException) 발생 > NPE방어 하기 위해 추가한 null check 추가 시 가독성 떨어짐
이러한 것을 개선하기 위해 JAVA8에 java.util.Optional<T>라는 새로운 클래스가 추가 됨

 

 

Optional이란?

  • 존재할수도 있지만 안할 수도 있는 객체, null이 될 수도 있는 객체를 감싸고 있는 일종의 래퍼 클래스
  • 기존엔 객체를 직접 null인지 체크 했지만 optional 담아서 쓰면 null 다루기가 좋아짐

 

Optional의 효과

  • 명시적으로 해당 변수가 null일 수도 있다는 가능성을 표현할 수 있
  • NPE를 유발할 수 있는 null을 직접 다루지 않아도
  • null체크를 직접 하지 않아도
     

Optional 기본 사용법

  • Optional 선언
    • 제네릭을 제공하기 때문에, 변수를 선언할 때 작성한 타입 파라미터에 따라서 감쌀 수 있는 객체의 타입이 결정됨
    • 변수명은 maybe나 opt 같은 접두어를 붙여서 Optional타입이라는 것을 알리기도
    • Optional<Order> optOrder;
  • 객체 생성
    • Optional.empty()
      • null을 담고 있는 Optional 객체를 얻어옴
      • 비어있는 객체는 Optional 내부적으로 미리 생성해 놓은 싱글턴 인스턴스
      • Optional<User> optUser = Optional.empty()
    • Optional.of(value)
      • null이 아닌 객체를 담고 있는 Optional 객체를 생성
      • null이 넘어올 경우, NPE를 던지기 때문에 주의해서 사용
      • Optional<User> optUser = Optional.of(user);
    •  Optional.ofNullable(value)
      • null인지 아닌지 확신할 수 없는 객체를 담고 있는 Optional 객체 생성
      • Optional.empty()와 Optional.of(value)를 합쳐놓은 메소드
      • Optional.of(value) 경우 null 넘어오게 되면 NPE 던지지만 이건 null 넘어오면 비어있는 Optional 객체를
      • 해당 객체가 null인지 아닌지 자신없는 상황에서는 이 메소드를 사용
      • Optional<User> optUser = Optional.ofNullable(null);

 

Optional 객체 존재 여부 확인

  • 옵셔널은 Null 수도 아닐 수도 있기 때문에 객체가 존재하는지 아니면 비어있는지 확인을 해야
  • 아래 메소드를 활용하여 존재 여부를 확인하여 로직을 진행하도록 분기 처리를 있음
  • isPresent( )
    • boolean 반환하는 메소드
    • Optional.isPresent() 경우 객체가 존재하면 true 리턴되고, 비어있는 경우 false 리턴
    •  
    • Optional<String> optStr = Optional.ofNullable("test"); if (optStr.isPresent()) { System.out.println(optStr.get()); }
  • ifPresent( )
    • Optional.ifPresent(Cosumer<? super String> consumer>)
    • 옵셔널에 객체가 존재하면 ( ) 가로 안에 작업을 진행하라는 메소드
    • 턴되는 void
    • Optional<String>optStr=Optional.ofNullable("test");
      optStr.ifPresent(str->System.out.println(str));

 

Optional이 담고 있는 객체 접근

  • Optional 클래스는 담고 있는 객체를 꺼내오기 위해서 다양한 인스턴스 메소드를 제공
  • 아래 메소드 모두 Optional이 담고 있는 객체가 존재할 경우 동일하게 해당 값을 반환하고 비어 있는 경우 작동이 다르기 때문에 특징을 알아야
  • get( )
    • 비어있는 Optional 객체에 대해서, NoSuchElementException을 던짐
    • 비어있지 않은 Optional 사용해야
  • orElse(T other)
    • 옵셔널이 비어 있다면 파라미터로 입력한 인자를 리턴하게
  • orElseGet(Supplier<? extends T> other)
    • 비어있는 Optional 객체에 대해서, 넘어온 함수형 인자를 통해 생성된 객체를 반환
    • orElse(T other) 메소드와 동일하게 리턴 하지만 비어있는 경우만 함수를 호출해서 성능상 이점 기대 가능
  • orElseThrow(Supplier<? extends X> exceptionSupplier)
    • 비어 있는 Optional객체에 대해, 넘어온 함수형 인자를 통해 생성된 예외를 던짐

 

 

실무에서 사용한 Optional 간단 예시

실무를 하면서 Optional 가장 많이 사용하는 것이 DB에서 데이터를 조회하는 경우이다. 현재 진행중인 프로젝트에서 JPA 사용하고 있고, 1건만 조회하는 경우 리턴 값을 optional 받고 있다. 참고로 JPA 단건 반환의 메소드의 경우 Optional 준다.

 

옵셔널로 받는 이유는 조건에 따라 조회를 하면 무조건 리턴되는 데이터가 있는 것이 아니기 때문이다. 리턴된 데이터가 없으면 에러를 내려줘야 하는 경우도 있고, 리턴된 데이터가 없으면 임의의 데이터를 추가해 줘야 하기 때문에 Optional 메소드를 활용하여 사용하고 있다.

 

특징이나 상세 설명처럼 optional 받으면 제공되는 메소드로 null 확인하거나 예외처리 등을 있다. 참고로 제대로 옵셔널을 활용하는 사람중에는 Stream처럼 사용하는 경우들이 있다. 그럼 소스 코드를 간단하게 작성할 있다.

Optional.ofNullable(user)
        .map(User::getGroup)
        .map(Group::getName)
        .orElse("Team1");

 

 

프로젝트에서 JPA Optional 사용한 간단한 예시 코드는 아래와 같다. 아마 예시를 보면 이런식으로 쓰는구나 라고 이해하기 좋을 것이다.

 

JPA repository 인터페이스에서 내가 조회하고자 하는 메소드를 추가하고, 해당 데이터를 조회해 오는 코드에서 사용한다. Optional 받아도 되지만 해당 이름을 가진 유저가 무조건 나와야 하는 경우에는 아래와 같이 없는 경우 에러를 던지게 처리할 있다. 일반적으로 프론트에서 해당 사원을 데이터를 주고 그걸 조회하기 떄문에 데이터가 없는 경우 에러를 내리게 처리했다.

 

JPA repository code

@Repository
public interface UserRepository extends JpaRepository<UserEntity, Long> {
    Optional<UserEntity> findByName(String Name);
}

 

Service class code

String name = "sun";
UserEntity optUserEntity = userRepository.findByName(name)
          .orElseThrow(() -> new EmptyDataException("해당 이름을 가진 유저가 데이터가 없음"));

 

Optional의 특징과 관련 메소드에 대해 알아보고, 실무 코드에서 사용하는 간단한 예시를 알아봤다. 이정도 알면 남에게 옵셔널에 대해 말할 수 있게 정리는 되지 않을까 한다. 기술 면접에서 옵셔널을 사용해 봤는지, 설명해 보라는 질문을 받으면 간단하게 설명할 수 있을 것이다!

반응형

댓글