공식 문서을 읽어보면 나온다.
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을 사용 하는게 좋을 수도 있고 아닐 수도 있습니다 으게겍..
공부에 많이 참고가 되었습니다 🙆🏻♂️