728x90
반응형
Optional 제대로 쓰기
Optional에 대해 공부를 해보다가 좋은 예제들이 있어서 적어봅니다.
출처를 남겼으며 나머지 내용들도 확인해 보시면 좋을것 같습니다.
옵셔널 변수에 널값 사용하지 않기
Optional 을 쓸때는 null 지옥을 피하기위해 사용함으로 null 값을 쓰는것은 의미가 없다.
// AVOID
public Optional<Cart> fetchCart() {
Optional<Cart> emptyCart = null;
...
}
// PREFER
public Optional<Cart> fetchCart() {
Optional<Cart> emptyCart = Optional.empty();
...
}
Get을 쓰기전에 값 존재 여부확인
// AVOID
Optional<Cart> cart = ... ; // this is prone to be empty
...
// if "cart"is empty then this code will throw a java.util.NoSuchElementException
Cart myCart = cart.get();
// PREFER
if (cart.isPresent()) {
Cart myCart = cart.get();
... // do something with "myCart"
} else {
... // do something that doesn't call cart.get()
}
디폴트 값이 있다면 orElse 를 사용하자
// AVOID
public static final String USER_STATUS = "UNKNOWN";
...
public String findUserStatus(long id) {
Optional<String> status = ... ; // prone to return an empty Optional
if (status.isPresent()) {
return status.get();
} else {
return USER_STATUS;
}
}
// PREFER
public static final String USER_STATUS = "UNKNOWN";
...
public String findUserStatus(long id) {
Optional<String> status = ... ; // prone to return an empty Optional
return status.orElse(USER_STATUS);
}
orElse 대신 orElseGet 을 쓰자
orElse 같은 경우는 optional 이 비워져 있지 않아도 평가 연산을 수행한다.
// AVOID
public String computeStatus() {
... // some code used to compute status
}
public String findUserStatus(long id) {
Optional<String> status = ... ; // prone to return an empty Optional
if (status.isPresent()) {
return status.get();
} else {
return computeStatus();
}
}
// PREFER
public String computeStatus() {
... // some code used to compute status
}
public String findUserStatus(long id) {
Optional<String> status = ... ; // prone to return an empty Optional
// computeStatus() is called only if "status" is empty
return status.orElseGet(this::computeStatus);
}
값이 없는 경우 익셉션을 던지자
// AVOID
public String findUserStatus(long id) {
Optional<String> status = ... ; // prone to return an empty Optional
if (status.isPresent()) {
return status.get();
} else {
throw new IllegalStateException();
}
}
// PREFER
public String findUserStatus(long id) {
Optional<String> status = ... ; // prone to return an empty Optional
return status.orElseThrow();
}
// PREFER
public String findUserStatus(long id) {
Optional<String> status = ... ; // prone to return an empty Optional
return status.orElseThrow(IllegalStateException::new);
}
값이 존재 할때만 메소드를 실행하고 싶은 경우
// AVOID
Optional<String> status = ... ;
...
if (status.isPresent()) {
System.out.println("Status: " + status.get());
}
// PREFER
Optional<String> status ... ;
...
status.ifPresent(System.out::println);
값 존재 여부에 따라 처리를 해야 될때
// AVOID
Optional<String> status = ... ;
if(status.isPresent()) {
System.out.println("Status: " + status.get());
} else {
System.out.println("Status not found");
}
// PREFER
Optional<String> status = ... ;
status.ifPresentOrElse(
System.out::println,
() -> System.out.println("Status not found")
);
생성자에 Optional 값을 쓰지 말자
// AVOID
public class Customer {
private final String name; // cannot be null
private final Optional<String> postcode; // optional field, thus may be null
public Customer(String name, Optional<String> postcode) {
this.name = Objects.requireNonNull(name, () -> "Name cannot be null");
this.postcode = postcode;
}
public Optional<String> getPostcode() {
return postcode;
}
...
}
// PREFER
public class Customer {
private final String name; // cannot be null
private final String postcode; // optional field, thus may be null
public Cart(String name, String postcode) {
this.name = Objects.requireNonNull(name, () -> "Name cannot be null");
this.postcode = postcode;
}
public Optional<String> getPostcode() {
return Optional.ofNullable(postcode);
}
...
}
컬렉션 리턴 타입에 옵셔널을 쓰지말자
- 대신 Collections.emptyList() 를 사용하자
// AVOID
public Optional<List<String>> fetchCartItems(long id) {
Cart cart = ... ;
List<String> items = cart.getItems(); // this may return null
return Optional.ofNullable(items);
}
// PREFER
public List<String> fetchCartItems(long id) {
Cart cart = ... ;
List<String> items = cart.getItems(); // this may return null
return items == null ? Collections.emptyList() : items;
}
Optional.of() 와 Optional.ofNullable() 을 혼동하지 말자
// AVOID
public Optional<String> fetchItemName(long id) {
String itemName = ... ; // this may result in null
...
return Optional.of(itemName); // this throws NPE if "itemName" is null :(
}
// PREFER
public Optional<String> fetchItemName(long id) {
String itemName = ... ; // this may result in null
...
return Optional.ofNullable(itemName); // no risk for NPE
}
Optional<T> 사용을 지양하자 대신 OptionalInt, OptionalLong, or OptionalDouble 쓰자!
// AVOID
Optional<Integer> price = Optional.of(50);
Optional<Long> price = Optional.of(50L);
Optional<Double> price = Optional.of(50.43d);
// PREFER
OptionalInt price = OptionalInt.of(50); // unwrap via getAsInt()
OptionalLong price = OptionalLong.of(50L); // unwrap via getAsLong()
OptionalDouble price = OptionalDouble.of(50.43d); // unwrap via getAsDouble()
Asserting Equality 을 수행 할때 UnWrap을 할 필요가 없다
// AVOID
Optional<String> actualItem = Optional.of("Shoes");
Optional<String> expectedItem = Optional.of("Shoes");
assertEquals(expectedItem.get(), actualItem.get());
// PREFER
Optional<String> actualItem = Optional.of("Shoes");
Optional<String> expectedItem = Optional.of("Shoes");
assertEquals(expectedItem, actualItem);
특정값을 조건처리할때 filter 를 쓰자.
// AVOID
public boolean validatePasswordLength(User userId) {
Optional<String> password = ...; // User password
if (password.isPresent()) {
return password.get().length() > 5;
}
return false;
}
// PREFER
public boolean validatePasswordLength(User userId) {
Optional<String> password = ...; // User password
return password.filter((p) -> p.length() > 5).isPresent();
}
Optional 값을 비교 할때 equals 를 쓰자
// AVOID
Product product = new Product();
Optional<Product> op1 = Optional.of(product);
Optional<Product> op2 = Optional.of(product);
// op1 == op2 => false, expected true
if (op1 == op2) { ..
// PREFER
Product product = new Product();
Optional<Product> op1 = Optional.of(product);
Optional<Product> op2 = Optional.of(product);
// op1.equals(op2) => true,expected true
if (op1.equals(op2)) { ...
출처:
https://dzone.com/articles/using-optional-correctly-is-not-optional
728x90
반응형
'Language > Java' 카테고리의 다른 글
[Java] sort, nullsLast, nullsFirst (0) | 2024.03.17 |
---|---|
[Java] Optional<T> 기본 (0) | 2023.02.06 |
[Java] SQL Mapper 만들기 (0) | 2022.10.20 |
[Java] Generic 메서드 (0) | 2022.06.25 |
[Java] Generic 와일드 카드 (0) | 2022.06.25 |
댓글