ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Java Optional 1
    JAVA 2022. 1. 25. 15:15

    요즘 느끼는거지만. Stream만 자주쓰다보니 다른 java8 에관련된걸 조금씩 잊어간다 하나씩 정리하면서 예제를좀 올려야 될듯 합니다

    1. Optional 이란?

    Java8에서는 Optional<T> 클래스를 사용해 NPE(Null Point Exception)를 방지할 수 있도록 도와준다.  Optional<T>는 

    null이 올 수 있는 값을 감싸는 Wrapper 클래스로

    , 참조하더라도 NPE가 발생하지 않도록 도와준다. Optional 클래스는 아래와 같은 value에 값을 저장하기 때문에 null이더라도 바로 NPE가 발생하지 않으며,
    클래스이기 때문에 각종 메소드를 제공해준다.

    • 예제 1-1> npe 예제
      public class OptionalJavaOptional<Member> memberOptional = Optional.empty();
              System.out.println("memberOptional = " + memberOptional);{
          public static void main(String[] args) {
              Member member1 = new Member(1L, "hello1");
              Member member2 = new Member(null, null);
              List<Member> memberList = new ArrayList<>(List.of(member1, member2));
              // NPE 발생
              memberList.sort(Comparator.comparing(Member::getId));
              // NPE 발생
              switch (member2.getName()) {
                  case "hello1" :
                      System.out.println("member1 = " + member1);
                      break;
                  case "hello2" :
                      System.out.println("member2 = " + member2);
                  default:
              }
          }
      
      	  @Data
          static class Member {
              Long id;
              String name;
              String email;
      
              public Member(Long id, String name) {
                  this.id = id;
                  this.name = name;
              }
          }
      }

    위 코드처럼 처리할시 member2.getName() 처리시 if 문을 사용하여 처리를 합니다

    if (member2.getName() == null) {
                member2.setId(2L);
                member2.setName("hello2");
            }

    if 문사용시 우리는 null 이 사용된 부분을 항상 체크해야합니다 → 이부분을 간편하게 하기위해 Optional을 활용 합니다.

    Optional 의 장접

    • NPE를 유발할 수 있는 null을 직접 다루지 않아도 됩니다.
    • 번거롭게 null 체크를 직접 하지 않아도 됩니다.
    • 명시적으로 해당 변수가 null일 수도 있다는 가능성을 표현할 수 있습니다. (따라서 불필요한 방어 로직을 줄일 수 있습니다.)

    2. Optional 활용

    Optional은 Wrapper 클래스 입니다 → 빈값이 생성될 수 있다. → Optional 내부적으로 미리 생성해 놓은 싱글턴 인스턴스

    • Optional.empty();
    Optional<Member> memberOptional = Optional.empty();
    System.out.println("memberOptional = " + memberOptional);
    //"memberOptional = Optional.empty"
    • Optional.of(value), Optional.ofNullable(value). of 와 ofNullable의 차이는 명확합니다 null 값이 넘어올 경우 NPE를 던지냐 안던지냐 입니다.
    Optional<Member> maybeMember = Optional.of(member1);
    Optional<Member> maybeMember = Optional.ofNullable(member2);
    Optional<Member> maybeNotMember = Optional.ofNullable(null);
    • get()
      꺼내서 보여주기만, null 인경우는 → NoSuchElemecntException을 던집니다.
    • orElseThorw(Supplier<? extedns T> exceptionSUpplier)
      비어있는 Optional 객체에 대해서, 넘어온 함수영 인자를 통해 생성된 예외를 던집니다.
    • orElse(T other)
      비어있는 Optional 객체에 대해서, 넘어온 인자를 반환합니다.
    • orElseGet(Supplier<? extedns T> other)
      비어 있는 Optional 객체에 대해서, 넘어온 한수영 인자를 통해 생성된 객체를 반환합니다.

    orElse 와 orElseGet의 차이점을 한번 볼까요??

    • 예제 2-1
      Member member1 = new Member(1L, "hello1");
      Member member2 = new Member(null, null);
      List<Member> memberList = new ArrayList<>(List.of(member1, member2));
      
      Optional<String> optionalS1 = Optional.ofNullable(member1.getName());
      Optional<String> optionalS2 = Optional.ofNullable(member2.getName());
      String orElse1 = optionalS1.orElse("this is null");
      String orElse2 = optionalS2.orElse("this is null");
      System.out.println("orElse1 = " + orElse1);
      System.out.println("orElse2 = " + orElse2);
      
      String orElseGet1 = optionalS1.orElseGet(() -> "this is null");
      String orElseGet2 = optionalS2.orElseGet(() -> "this is null");
      System.out.println("orElseGet1 = " + orElseGet1);
      System.out.println("orElseGet2 = " + orElseGet2);
      /*
      orElse1 = hello1
      orElse2 = this is null
      orElseGet1 = hello1
      orElseGet2 = this is null
      */

    예제 2-1 의 결과를 보면 둘의 반환값은별 차이가 없어보입니다. 실제 null 이 들어오면 처리해주는것이 같은걸 확인할수 있죠 하지만,

    아래 코드를 추가후 한번 아래 메소드를 불러오는 식으로 처리를 해보겠습니다.

    public static String createMemberEmail(List<Member> list,String email) {
            Member member = new Member(3L, "hello3");
            member.setEmail(email);
            list.add(member);
            return email;
        }
    • 예제 2-2
      Member member1 = new Member(1L, "hello1");
      Member member2 = new Member(null, null);
      List<Member> memberList = new ArrayList<>(List.of(member1, member2));
      
      Optional<String> optionalS1 = Optional.ofNullable(member1.getName());
      String orElseGetProceedMethod = optionalS1.orElseGet(() ->createMemberEmail(memberList, "@Gmail.com"));
      System.out.println("emailOrElseGet = " + orElseGetProceedMethod);
      System.out.println("memberList = " + memberList);
      
      String orElseProceedMethod = optionalS1.orElse(createMemberEmail(memberList, "@Gmail.com"));
      System.out.println("emailOrElse = " + orElseProceedMethod);
      System.out.println("memberList = " + memberList);
      /*
      emailOrElseGet = hello1
      memberList = 
      	[OptionalJava.Member(id=1, name=hello1, email=null), OptionalJava.Member(id=null, name=null, email=null)]
      
      emailOrElse = hello1
      memberList = 
      	[OptionalJava.Member(id=1, name=hello1, email=null), OptionalJava.Member(id=null, name=null, email=null), OptionalJava.Member(id=3, name=hello3, email=@Gmail.com)]
      */

    orElse → null이 이든 null 이 아니든 orElse에 사용하였던 method가 처리가 되지만, orElseGet → 은 null 값이 들어와야지만 method가 처리 됩니다. 실제, orElseGet의 경우 2개의 값이 memberList에 들어와있고, orElse의 경우 3개의 값이 들어와 있습니다.

    3. Optional의 잘못된 사용

    사실 저도 Optional을 처음 사용할때는 if 체크로 하는게 더 쉽지 않나?? 굳이 왜 저렇게 쓸까 하고 많은 생각을 햇었던거 같습니다.

    정확히는 Optional을 사용하면 null 체크를 할 필요가 없는것입니다. → null 처리를 Optional 클래스에 위임하기 위함입니다.

    • 예제 3-1> 기존의 방식
      for (Member member : memberList) {
          Optional<Member> optionalMember = Optional.ofNullable(member);
          if (optionalMember.isPresent()) {
              Optional<String> name = Optional.ofNullable(member.getName());
              if (name.isPresent()) {
                  System.out.println("name.get() = " + name.get());
              } else {
                  System.out.println("name.orElse() = " + name.orElse("new Hello"));
              }
          }
      }
      /*
      name.get() = hello1
      name.orElse() = new Hello
      */
    • 예제 3-2> Optional 적인 생각
      for (Member member : memberList) {
      		String optionalMemberGetName = Optional.ofNullable(member.getName()).orElseGet(() -> "new Hello");
      		System.out.println("optionalMemberGetName = " + optionalMemberGetName);
      }
      /*
      optionalMemberGetName = hello1
      optionalMemberGetName = new Hello
      */

    예제 3-2 처럼(완벽하진 않지만) 기존 null을 대하던 생각을

    함수형사고

    로 완전히 새롭게 바꿔야 합니다.

     

    참조 : https://www.daleseo.com/java8-optional-after/

     

    'JAVA' 카테고리의 다른 글

    Pattern  (0) 2022.02.15
    Java Optional2  (1) 2022.02.03

    댓글

Designed by Tistory.