Optional 기본
{{< youtube vX3yY_36Sk4 >}}
영상 요약
서적 지식
int, long, double 등의 원시형 데이터를 다룰 때에는
OptionalInt, OptionalLong, OptionalDouble와 같은 전용클래스를 이용하면 랩퍼 형으로 형변환을 하지 않아도 되므로 효율적인 옵셔널을 사용하기에 좋다.
원시형 데이터 에서의 Null을 다룰 때에는 꼭 써보자
기본구문
옵셔널 오브젝트의 생성법
public class Exercise1 {
public static void main(String[] args) {
// of의 경우에는 직접 null을 넣으면 예외로 스로우 된다.
Optional<String> exist = Optional.of("abc");
System.out.println(exist);
// 값을 갖고 있지 않은 비어있는 옵셔널 오브젝트 생
Optional<String> empty = Optional.empty();
System.out.println(empty);
// 값이 null이외일경우 에는 값을 갖고 있는 옵셔널,
// 값이 null일 때에는 비어있는 옵셔널이 된다.
String value = "";
Optional<String> optional = Optional.ofNullable(value);
System.out.println(optional);
value = null;
System.out.println(optional);
// 제일 위에 코드에 null을 직접 대입해보자
Optional<String> exist2 = Optional.of(null);
System.out.println(exist2);
}
}
Optional[abc]
Optional.empty
Optional[]
Optional[]
Exception in thread "main" java.lang.NullPointerException
at java.util.Objects.requireNonNull(Objects.java:203)
at java.util.Optional.<init>(Optional.java:96)
at java.util.Optional.of(Optional.java:108)
at MapExercise.Exercise1.main(Exercise1.java:27)
옵셔널 로부터 값을 갖고 오는 법
public class Exercise1 {
public static void main(String[] args) throws Exception {
String name = "James";
Optional<String> optionalName = Optional.ofNullable(name);
// String name 값이 null일경우 NoSuchElementException으로 스로우 된다
String value1 = optionalName.get();
// 값이 null일경우 공문자를 반환한다
String value2 = optionalName.orElse("");
// 값이 null일경우 람다식 결과를 반환한다
String value3 = optionalName.orElseGet(() -> {
return new SimpleDateFormat("yyyyMMddHHmmSS").format(new Date());
});
// 값이 null일경우 임의 지정 예외 처리를 한다
String value4 = optionalName.orElseThrow(() -> new Exception("값이 없습니다"));
}
}
nullpoint익셉션 에러를 피하기 위해서 옵셔널을 쓰는데..
첫번째 코드는 사실상 안쓰일것 같다..? (익섹셥이 발생하니까..)
orElse / orElseGet / orElseThrow 모두 많이 보이기 때문에 필히 익혀두자
값이 있는경우만 처리하기 !(null이 아닐때에만)
public class Exercise1 {
public static void main(String[] args) throws Exception {
String name = "James";
Optional<String> nullableName = Optional.ofNullable(name);
if (nullableName.isPresent()) {
System.out.println(nullableName.get());
} else {
System.out.println("값이 없으면 처리가 이쪽으로 빠져요");
}
String name2 = null;
Optional<String> nullableName2 = Optional.ofNullable(name2);
if (nullableName2.isPresent()) {
System.out.println(nullableName2.get());
} else {
System.out.println("값이 없으면 처리가 이쪽으로 빠져요");
}
}
}
James
값이 없으면 처리가 이쪽으로 빠져요
실무에서 쓰면 아주아주아주 유용할 기술이다
값이 있는 경우에만 람다로 처리하기
public class Exercise1 {
public static void main(String[] args) throws Exception {
String name = "James";
Optional<String> nullableName = Optional.ofNullable(name);
nullableName.ifPresent(s -> System.out.println(s));
String name2 = null;
Optional<String> nullableName2 = Optional.ofNullable(name2);
nullableName2.ifPresent(s -> System.out.println(s));
}
}
James
두번째는 null이므로 람다 처리가 되지 않았다. 이것도 실무에 쓰면 아주 유용할듯
옵셔널과 필터링의 조합
filter()메서드를 사용하면.
조건에 부합할 때 처리 / 조건에 부합하지 않으면 비어있는 옵셔널 반환 식으로 사용할 수 있다.
public class Exercise1 {
public static void main(String[] args) throws Exception {
String name = "James";
Optional<String> nullableName = Optional.ofNullable(name);
nullableName.filter(s -> s.length() > 4)
.ifPresent(p -> {
System.out.println(p);
});
nullableName.filter(s -> s.length() > 5)
.ifPresent(p -> {
System.out.println(p);
});
nullableName.filter(s -> s.length() >= 5)
.ifPresent(p -> {
System.out.println(p.toUpperCase());
});
}
}
James
JAMES
옵셔널과 map 조합으로 새로운 옵셔널에 맵핑
public class Exercise1 {
public static void main(String[] args) throws Exception {
String name = "James";
Optional<String> nullableName = Optional.ofNullable(name);
Optional<String> mappedName = nullableName.map(s -> s.toUpperCase());
mappedName.ifPresent(s -> System.out.println(s));
String name2 = null;
Optional<String> nullableName2 = Optional.ofNullable(name2);
Optional<String> mappedName2 = nullableName2.map(s -> s.toUpperCase());
mappedName2.ifPresent(s -> System.out.println(s));
}
}
JAMES
두번째는 null이므로 출력이 안된다(비어있는 옵셔널 객체)
복수의 옵셔널을 동시에 사용해보기
public class Exercise1 {
public static void main(String[] args) throws Exception {
String userName = "David";
String password = "Father";
Optional<String> nullableName = Optional.ofNullable(userName);
Optional<String> nullablePassword = Optional.ofNullable(password);
boolean isValid = nullableName.flatMap(n -> {
return nullablePassword.map(p -> {
return n.equals("David") && p.equals("Father");
});
}).orElse(false);
System.out.println(isValid);
// 한쪽에 null을 넣어봄
String idCard = null;
String cardPassword = "Brother";
Optional<String> nullableIdCard = Optional.ofNullable(idCard);
Optional<String> nullableCardPassword = Optional.ofNullable(cardPassword);
boolean getValidInform = nullableIdCard.flatMap(n -> {
return nullableCardPassword.map(p -> {
return n.equals("Joly") && p.equals("Brother");
});
}).orElse(false);
System.out.println(getValidInform);
}
}
true
false
한쪽에 null이 있을경우 비어있는 옵셔널이 반환되므로
orElse메서드의 디폴드 값인 false가 최종적으로 반환된다
실무
이분이 정말 잘 정리 해주셨다. 이분사이트를 참고하면 정말 좋은 예제를 볼 수 있다.
링크 : Java Optional바르게 쓰기
백기선님의 좋은 예제 링크 : 자바 Optional의 ifPresent활용하기
실무에서 다음과 같은 코드가 있었다.(리팩토링을 못하게 하는 현장이라 손을 댈 수 없었지만 이코드가 신경이 쓰이길래 구글링을 해봤다)
Optional<Employee> employeeData = getEmployeeData(employeeCD);
if (employeeData.isPresent()) {
Employee employee = employeeData.get();
// 조건에 따른 처리
} else {
// 조건에 따른 처리
}
위의 코드를 이렇게 바꾼다.(첫번째 링크분의 조언 - isPresent()get()대신 orElse() / orElseGet() / orElseThrow())
Optional<Employee> employeeData = getEmployeeData(employeeCD);
employeeData.orElseGet(Employee::new);
// 처리
혹은 백기선님의 조언대로 한다면 이렇게 된다
Optional<Employee> employeeData = getEmployeeData(employeeCD);
employeeData.ifPresent(employee -> {
// 처리
})