List<String> names = getNames();
names.sort(); // names가 null이라면 NPE가 발생함
List<String> names = getNames();
// NPE를 방지하기 위해 null 검사를 해야함
if(names != null){
names.sort();
}
Optional<User> optionalUser = ... ;
// optional이 갖는 value가 없으면 NoSuchElementException 발생
User user = optionalUser.get();
public void temp(Optional<User> optionalUser) {
User user = optionalUser.orElseThrow(IllegalStateException::new);
// 이후의 후처리 작업 진행...
}
public void temp(Optional<User> optionalUser) {
if (optionalUser != null && optionalUser.isPresent()) {
// 이후의 후처리 작업 진행...
}
throw new IllegalStateException();
}
private String findDefaultName() {
return ...;
}
// AVOID
public String findUserName(long id) {
Optional<String> optionalName = ... ;
if (optionalName.isPresent()) {
return optionalName.get();
} else {
return findDefaultName();
}
}
// PREFER
public String findUserName(long id) {
Optional<String> optionalName = ... ;
return status.orElseGet(this::findDefaultName);
}
// AVOID
public String findUserName(long id) {
String name = ... ;
return Optional.ofNullable(name).orElse("Default");
}
// PREFER
public String findUserName(long id) {
String name = ... ;
return name == null ? "Default" : name;
}
// AVOID
public class User {
private final String name;
private final Optional<String> postcode;
public Customer(String name, Optional<String> postcode) {
this.name = Objects.requireNonNull(name, () -> "Cannot be null");
this.postcode = postcode;
}
public Optional<String> getName() {
return Optional.ofNullable(name);
}
public Optional<String> getPostcode() {
return postcode;
}
}
// AVOID
public Optional<List<User>> getUserList() {
List<User> userList = ...; // null이 올 수 있음
return Optional.ofNullable(items);
}
// PREFER
public List<User> getUserList() {
List<User> userList = ...; // null이 올 수 있음
return items == null ? Collections.emptyList() : userList;
}
// AVOID
public Map<String, Optional<String>> getUserNameMap() {
Map<String, Optional<String>> items = new HashMap<>();
items.put("I1", Optional.ofNullable(...));
items.put("I2", Optional.ofNullable(...));
Optional<String> item = items.get("I1");
if (item == null) {
return "Default Name"
} else {
return item.orElse("Default Name");
}
}
// PREFER
public Map<String, String> getUserNameMap() {
Map<String, String> items = new HashMap<>();
items.put("I1", ...);
items.put("I2", ...);
return items.getOrDefault("I1", "Default Name");
}
Optional<String> optional = Optional.empty();
System.out.println(optional); // Optional.empty
System.out.println(optional.isPresent()); // false
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
private Optional() {
this.value = null;
}
...
}
// Optional의 value는 절대 null이 아님
Optional<String> optional = Optional.of("MyName");
// Optional의 value는 값이 있을 수도 있고 null 일 수도 있음
Optional<String> optional = Optional.ofNullable(getName());
String name = optional.orElse("anonymous"); // 값이 없다면 "anonymous" 를 리턴
public void findUserEmailOrElse() {
String userEmail = "Empty";
String result = Optional.ofNullable(userEmail)
.orElse(getUserEmail());
System.out.println(result);
}
private String getUserEmail() {
System.out.println("getUserEmail() Called");
return "eminem@hiphop.com";
}
/* 처리 과정
1. Optional.ofNullable로 "EMPTY"를 갖는 Optional 객체 생성
2. getUserEmail()이 실행되어 반환값을 orElse 파라미터로 전달
3. orElse가 호출됨, "EMPTY"가 Null이 아니므로 "EMPTY"를 그대로 가짐
*/
/* 출력 결과
getUserEmail() Called
Empty
*/
public void findUserEmailOrElseGet() {
String userEmail = "Empty";
String result = Optional.ofNullable(userEmail)
.orElseGet(this::getUserEmail);
System.out.println(result);
}
private String getUserEmail() {
System.out.println("getUserEmail() Called");
return "eminem@hiphop.com";
}
/* 처리 과정
1. Optional.ofNullable로 "EMPTY"를 갖는 Optional 객체 생성
2. getUserEmail() 함수 자체를 orElseGet 파라미터로 전달
3. orElseGet이 호출됨, "EMPTY"가 Null이 아니므로 "EMPTY"를 그대로 가지며 getUserEmail()이 호출되지 않음
*/
/* 출력 결과
Empty
*/
public void findUserEmailOrElseGet() {
String result = Optional.ofNullable(userEmail)
.orElseGet(this::getUserEmail);
System.out.println(result);
}
private String getUserEmail() {
System.out.println("getUserEmail() Called");
return "eminem@hiphop.com";
}
/* 처리 과정
1. Optional.ofNullable로 null를 갖는 Optional 객체 생성
2. getUserEmail() 자체를 orElseGet 파라미터로 전달
3. orElseGet이 호출됨, 값이 Null이므로 other.get()이 호출되어 getUserEmail()가 호출됨
*/
public void findByUserEmail(String userEmail) {
// userEmail이 Unique한 경우 에러 발생
return userRepository.findByUserEmail(userEmail)
.orElse(createUserWithEmail(userEmail));
}
// 조회 결과와 무관하게 아래의 함수가 반드시 실행됨
private String createUserWithEmail(String userEmail) {
User newUser = new User(userEmail);
return userRepository.save(newUser);
}
// 파라미터로 createUserWithEmail 함수 자체가 넘어가게 됨
// 조회 결과가 없을 경우에만 사용자를 생성하는 로직 호출
public void findByUserEmail(String userEmail) {
// orElseGet에 의해 파라미터로 함수를 넘겨주므로 Null이 아니면 유저 생성 함수가 호출되지 않음
return userRepository.findByUserEmail(userEmail)
.orElseGet(createUserWithEmail(userEmail));
}
private String createUserWithEmail(String userEmail) {
User newUser = new User(userEmail);
return userRepository.save(newUser);
}
@Test
void optionalTest() {
String name = "eminem";
Optional<User> user = userRepository.findByName(name);
if (user.isPresent()) {
System.out.println("이미 존재하는 이름");
} else {
System.out.println("사용가능한 이름");
}
}
@Test
void optionalTest() {
Long id = 4L;
userRepository.findById(id).ifPresent(a -> {
throw new BadRequestException("이미 존재하는 이름");
})
System.out.println("사용가능한 이름");
}
// Java8 이전
List<String> names = getNames();
List<String> tempNames = list != null ? list : new ArrayList<>();
// Java8 이후
List<String> nameList = Optional.ofNullable(getNames())
.orElseGet(() -> new ArrayList<>());
// Java8 이전
public String findPostCode() {
UserVO userVO = getUser();
if (userVO != null) {
Address address = user.getAddress();
if (address != null) {
String postCode = address.getPostCode();
if (postCode != null) {
return postCode;
}
}
}
return "우편번호 없음";
}
// Java8 이후
public String findPostCode() {
// 위의 코드를 Optional로 펼쳐놓으면 아래와 같다.
Optional<UserVO> userVO = Optional.ofNullable(getUser());
Optional<Address> address = userVO.map(UserVO::getAddress);
Optional<String> postCode = address.map(Address::getPostCode);
String result = postCode.orElse("우편번호 없음");
// 그리고 위의 코드를 다음과 같이 축약해서 쓸 수 있다.
String result = user.map(UserVO::getAddress)
.map(Address::getPostCode)
.orElse("우편번호 없음");
}
// Java8 이전
String name = getName();
String result = "";
try {
result = name.toUpperCase();
} catch (NullPointerException e) {
throw new CustomUpperCaseException();
}
// Java8 이후
Optional<String> nameOpt = Optional.ofNullable(getName());
String result = nameOpt.orElseThrow(CustomUpperCaseExcpetion::new)
.toUpperCase();
참고 1 : https://mangkyu.tistory.com/70
참고 2 : https://mangkyu.tistory.com/203
참고 3 : https://cfdf.tistory.com/34