-
[Java]Optional 활용법JAVA 2021. 12. 17. 20:02
1. ifPresent() - get() 대신 orElse()/orElseGet()/orElseThrow() 쓰기
더 직관적으로, 코드를 한줄이라도 줄일 수있다.
// 안 좋은 예시 Optional<Member> member = ...; if (member.isPresent()) { return member.get(); } else { return null; } // 좋은 예시 Optional<Member> member = ...; return member.orElse(null); // 안 좋은 예시 Optional<Member> member = ...; if (member.isPresent()) { return member.get(); } else { throw new NoSuchElementException(); } // 좋은 예시 Optional<Member> member = ...; return member.orElseThrow(NoSuchElementException::new);
2. orElse(new ...) 대신 orElseGet(() -> new ...)
orElse(...)에서 ...는 Optional에 값이 있든 없는 무조건 실행된다. 따라서 ...가 새로운 객체를 생성하거나 새로운 연산을 수행하는 경우에는 orElse() 대신 orElseGet()을 써야한다.
// 안 좋은 예시 Optional<Member> member = ...; return member.orElse(new Member()); // member에 값이 있든 없든 new Member()는 무조건 실행됨 // 좋은 예시 Optional<Member> member = ...; return member.orElseGet(Member::new); // member에 값이 없을 때만 new Member()가 실행됨 // 좋은 예시 Member EMPTY_MEMBER = new Member(); ... Optional<Member> member = ...; return member.orElse(EMPTY_MEMBER); // 이미 생성됐거나 계산된 값은 orElse()를 사용해도 무방
3. Optional 대신 비어있는 컬렉션 반환
Optionl은 비싸다. 그리고 컬렉션은 null이 아니라 비어있는 컬렉션을 반환하는 것이 좋을 때가 많다. 따라서 컬렉션은 Optional로 감싸서 반환하지 말고 비어있는 컬렉션을 반환하는 것이 좋다.
// 안 좋은 예시 List<Member> members = team.getMembers(); return Optional.ofNullable(members); // 좋은 예시 List<Member> members = team.getMembers(); return members.isEmpty() ? Collections.emptyList() : members; // 안 좋은 예시 public interface MemberRepository<Member, Long> extends JpaRepository { Optional<List<Member>> findAllByNameContaining(String part); } // 좋은 예시 public interface MemberRepository<Member, Long> extends JpaRepository { List<Member> findAllByNameContaining(String part); // null이 반환되지 않으므로 Optional 불필요 }
4. Optional을 필드로 사용 금지
Optional은 필드에 사용할 목적으로 만들어지지 않았으며, Serializable을 구현하지 않았다. 따라서 Optional은 필드로 사용하지 않는 것이 좋다.
// 안 좋은 예시 public class Member { private Long id; private String name; private Optional<String> email = Optional.empty(); } // 좋은 예시 public class Member { private Long id; private String name; private String email; }
5. Optional을 생성하자나 메서드
Optional을 생성자나 메서드 인자로 사용하면, 호출할 때마다 Optional을 생성해서 인자로 전달해줘야 한다. 하지만 호출될 때마다 Optional을 생성해서 인자로 전달해줘야 한다. 하지만 호출되는 쪽, 즉 api나 라이브러리 메서드에서는 인자가 Optional이든 아니든 null 체크를 하는 것이 언제나 안전하다. 따라서 굳이 비싼 Optional을 인자로 사용하지말고 호출되는 족에 null 체크 책임을 남겨두는 것이 좋다.
// 안 좋은 예 public class HRManager { public void increaseSalary(Optional<Member> member) { member.ifPresent(member -> member.increaseSalary(10)); } } hrManager.increaseSalary(Optional.ofNullable(member)); // 좋은 예 public class HRManager { public void increaseSalary(Member member) { if (member != null) { member.increaseSalary(10); } } } hrManager.increaseSalary(member);
6. Optional을 컬렉션의 원소로 사용 금지
컬렉션에는 많은 원소가 들어갈 수 있다. 따라서 비싼 Optional을 원소로 사용하지 말고 원소를 떠날 때마다 사용할 때 null 체크하는 것이 좋다. 특히 Map은 getOrDefault(), putIfAbsent(), computeIfAbsent(), computeIfPresent()처럼 null 체크가 포함된 메서드를 제공하므로, Map의 원소로 Optional을 사용하지말고 Map이 제공하는 메서드를 활용하는 것이 좋다.
// 안 좋은 예 Map<String, Optional<String>> sports = new HashMap<>(); sports.put("100", Optional.of("BasketBall")); sports.put("101", Optional.ofNullable(someOtherSports)); String basketBall = sports.get("100").orElse("BasketBall"); String unknown = sports.get("101").orElse(""); // 좋은 예 Map<String, String> sports = new HashMap<>(); sports.put("100", "BasketBall"); sports.put("101", null); String basketBall = sports.getOrDefault("100", "BasketBall"); String unknown = sports.computeIfAbsent("101", k -> "");
출처 : Java Optional 바르게 쓰기 - 뒤태지존의 끄적거림 (homoefficio.github.io)
'JAVA' 카테고리의 다른 글
[Java] HashMap Value 기준으로 정렬하기 (0) 2022.01.13 [Java] Java 함수적 인터페이스 Consumer, Supplier (0) 2021.12.17 [Java] Optional (0) 2021.12.17 [Java] java8 stream (0) 2021.12.17 [Java] 메소드 참조(method reference) (0) 2021.12.16