공식 문서을 읽어보면 나온다.
API Note:
Optional is primarily intended for use as a method return type where there is a clear need to represent "no result," and where using null is likely to cause errors. A variable whose type is Optional should never itself be null; it should always point to an Optional instance.
없다는 것을 확실하게 표현할 수 있게 하려고 만든 것으로 표현한 것 같다.
이 친구가 참 괴상한 친구인 것이 사용할 때 주의사항이 26가지나 된다. 링크
나는 그래서 가급적 지양하는 편인데, 필요한 경우 아래를 지켜서 사용한다.
isPresent() - get() 대신 orElse() / orElseGet() / orElseThrow()// 안 좋은 코드
Optional<Member> member = ...;
if (member.isPresent()) {
return member.get();
} else {
return null;
}
// 안 좋은 코드
Optional<Member> member = ...;
if (member.isPresent()) {
return member.get();
} else {
throw new NoSuchElementException();
}
// 좋은 코드
Optional<Member> member = ...;
return member.orElse(null);
// 좋은 코드
Optional<Member> member = ...;
return member.orElseThrow(() -> new NoSuchElementException());
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()를 사용해도 무방.
Optional 대신 null 비교
Optional은 비싸다. 따라서 단순히 값 또는null을 얻을 목적이라면Optional대신null비교를 쓰자.
// 안 좋은 코드
return Optional.ofNullable(status).orElse(READY);
// 좋은 코드
return status != null ? status : READY;
Optional 대신 비어있는 컬렉션 반환
Optional은 비싸다. 그리고 컬렉션은null이 아니라 비어있는 컬렉션을 반환하는 것이 좋을 때가 많다. 따라서 컬렉션은Optional로 감싸서 반환하지 말고 비어있는 컬렉션을 반환하자.
// 안 좋은 코드
List<Member> members = team.getMembers();
return Optional.ofNullable(members);
// 좋은 코드
List<Member> members = team.getMembers();
return members != null ? members : Collections.emptyList();
// 안 좋은 코드
public interface MemberRepository<Memeber, Long> extends JpaRepository {
Optional<List <Member>> findAllByNameContaining(String part);
}
// 좋은 코드
public interface MemberRepository<Member, Long> extends JpaRepository {
List<Mbmer> findAllByNameContaining(String part);
}
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;
}
Optional 을 생성자나 메서드 인자로 사용 금지
Optional을 생성자나 메서드 인자로 사용하면, 호출할 떄마다Optional을 생성해서 인자로 전달해줘야 한다. 하지만 호출되는 쪽, 즉 api나 라이브러이 메서드에서는 인자가Optional이든 아니든null체크를 하는 것이 언제나 안전하다. 그러므로null체크를 하자.
// 안 좋은 코드
public class HRManager {
public void increaseSalary(Optional<Member> member) {
member.ifPresent(member -> memberincreaseSalary(10));
}
}
hrManager.increaseSalary(Optional.ofNullable(member));
// 좋은 코드
public class HRManager {
public void increaseSalary(Member member) {
if (member != null) {
member.increaseSalary(10);
}
}
}
hrManager.increaseSalary(member);
Optional을 컬렉션의 원소로 사용 금지컬렉션에는 많은 원소가 들어갈 수 있다. 따라서 비싼
Optional을 원소로 사용하지 말고 원소를 꺼낼 때나 사용할 때null체크하는 것이 좋다.
// 안 좋은 코드
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 -> "");
of() , ofNullable() 혼동 주의
of(X)은X가null이 아님이 확실할 때만 사용해야 하며,X가null이면 NullPointerException이 발생한다.
ofNullable(X)은X가null일 수도 있을 때만 사용해야 하며,X가null이 아님이 확실하면of(x)를 사용해야 한다.
// 안 좋은 코드
return Optional.of(member.getEmail());
// 안 좋은 코드
return Optional.ofNullable("READY");
// 좋은 코드
return Optional.ofNullable(member.getEmail());
// 좋은 코드
return Optional.of("READY");
Optional<T> 대신 OptionalInt, OptionalLong, OptionalDouble
Optional에 담길 값이int,long,double이라면 Boxing/Unboxing 이 발생하는Optional<Integer>,Optional<Long>,Optional<Double>을 사용하지 말고,OptionalInt,OptionalLong,OptionalDouble을 사용하자.
// 안 좋은 코드
Optional<Integer> count Optional.of(38);
for (int i = 0; i < count.get(); i++) { ... }
// 좋은 코드
Optional count = Optional.of(38);
for (int i = 0; i <count.getAsInt(); i++) { ... }
NPE 예방을 위해 대신 Optional을 사용 하는게 좋을 수도 있고 아닐 수도 있습니다 으게겍..
공부에 많이 참고가 되었습니다 🙆🏻♂️