일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- MAC address
- Kafka
- Trino
- Packet
- kubectl
- airflow
- CSV
- Operating System
- PostgreSQL
- helm
- EC2
- kubeadm
- jvm
- zookeeper
- Network
- CVAT
- grafana
- Spring
- Python
- kubernetes
- OS
- log
- aws s3
- JavaScript
- java
- tcp
- AWS
- docker
- Vision
- ip
- Today
- Total
JUST WRITE
Optional 본문
이 글은 Baeldung 사이트 'Guide To Java 8 Optional'를 해석, 정리한 글입니다.
Optional
Optional은 NullPointException으로부터 보호하면서 읽기 쉬운 코드로 작성되기 위해 도입되었다.
Java 8 에 java.util.Optional로 도입되었다.
Optional 객체 생성
Optional 객체는 empty, of, ofNullable Method 로 생성할 수 있다.
- empty -> 비어 있는 Optional 객체 생성
- of -> Argument로 들어오는 객체로 감싼 Optianl 객체 생성, Null이 들어오면 NullPointerException 발생
- ofNullable -> Argument로 들어오는 객체(Null도 상관 없음)로 감싼 Optianl 객체 생성
public void createOptionalObjects() {
Optional<String> empty = Optional.empty();
String name = "baeldung";
Optional<String> opt = Optional.of(name);
Optional<String> opt = Optional.of(null); // NullPointerException 발생!!!
String name = "baeldung";
Optional<String> opt = Optional.ofNullable(name);
}
Optional 객체 Value Check
Optional 객체 저장된 값을 Check 하려면 isPresent, isEmpty Method로 확인할 수 있다.
isEmpty Method는 Java 11부터 도입되었다.
public void checkOptionalValue() {
Optional<String> opt = Optional.of("Baeldung");
Sytem.out.print(opt.isPresent()); // true
opt = Optional.ofNullable(null);
Sytem.out.print(opt.isEmpty()); // true
}
우리는 간혹 Null Check 하는 것을 놓칠 수 있다.
그래서 ifPresent Method를 활용하여 값이 있을때만 실행되도록 할 수 있다.
@Test
public void givenOptional_whenIfPresentWorks_thenCorrect() {
Optional<String> opt = Optional.of("baeldung");
opt.ifPresent(name -> System.out.println(name.length()));
}
/*
* ifPresent를 쓰면 아래 코드 따로 작성할 필요 X
*/
if(name != null) {
System.out.println(name.length());
}
orElse vs orElseGet vs orElseThrow
orElse vs orElseGet
두 Method 모두 Optional 객체에 값이 없을 때 Default 값을 return 해준다.
public void checkProcessOrElse() {
// orElse
String nullName1 = null;
String name1 = Optional.ofNullable(nullName1).orElse("john");
System.print.out(name1); // john
// orElseGet
String nullName2 = null;
String name2 = Optional.ofNullable(nullName2).orElseGet(() -> "john");
System.print.out(name2); // john
}
다만 두 Method는 아래와 같은 차이점이 있다.
- orElse -> Optional 객체의 값에 상관없이 Call
- orElseGet -> Optional 객체의 값이 비어 있을때만 Call
public String getMyDefault() {
System.out.println("Getting Default Value");
return "Default Value";
}
public void whenOrElseGetAndOrElseOverlap_thenCorrect() {
String text = null;
String defaultText = Optional.ofNullable(text).orElseGet(this::getMyDefault);
assertEquals("Default Value", defaultText);
defaultText = Optional.ofNullable(text).orElse(getMyDefault());
assertEquals("Default Value", defaultText);
}
// null일때는 orElse, orElseGet 모두 실행(print)
Getting default value...
Getting default value...
@Test
public void whenOrElseGetAndOrElseDiffer_thenCorrect() {
String text = "Text present";
System.out.println("Using orElseGet:");
String defaultText = Optional.ofNullable(text).orElseGet(this::getMyDefault);
assertEquals("Text present", defaultText);
System.out.println("Using orElse:");
defaultText = Optional.ofNullable(text).orElse(getMyDefault());
assertEquals("Text present", defaultText);
}
// 값이 있을때 orElse만 실행(print)
Using orElseGet:
Using orElse:
Getting default value...
orElseThrow
Optional 객체에 값을 return 해주는데 값이 없으면 사용자가 정의한 Exception을 발생한다.
Java 10에서는 Argument 없는 orElseThrow가 제공되었다.
Argument 없는 Method 사용 시 NoSuchElementExeption을 발생한다.
@Test(expected = IllegalArgumentException.class)
public void whenOrElseThrowWorks_thenCorrect() {
String nullName = null;
String name = Optional.ofNullable(nullName).orElseThrow(
IllegalArgumentException::new);
}
// No Argument orElseThrow Method
@Test(expected = NoSuchElementException.class)
public void whenNoArgOrElseThrowWorks_thenCorrect() {
String nullName = null;
String name = Optional.ofNullable(nullName).orElseThrow();
}
fiter
filter Method는 보통 정의된 규칙에 따른 값을 선별할 때 사용한다.
예를 들어 Email, Password Format을 선별할 때 유용하다.
보통 map Method와 함께 사용한다.
public class Modem {
private Double price;
public Modem(Double price) {
this.price = price;
}
// standard getters and setters
}
// No Optional
public boolean priceIsInRange1(Modem modem) {
boolean isInRange = false;
if (modem != null && modem.getPrice() != null
&& (modem.getPrice() >= 10
&& modem.getPrice() <= 15)) {
isInRange = true;
}
return isInRange;
}
// Optional filter 활용
public boolean priceIsInRange2(Modem modem2) {
return Optional.ofNullable(modem2)
.map(Modem::getPrice)
.filter(p -> p >= 10)
.filter(p -> p <= 15)
.isPresent();
}
Optional 잘못된 사용
Optional을 Method Parameter에 정의해서 사용하면 안 된다.
Parameter에 정의해서 사용하게 되면 NullPointerException이 발생할 상황이 생긴다.
그렇게 된다면 Optional 사용할 필요가 없다.
public static List<Person> search(List<Person> people, String name, Optional<Integer> age) {
// Null checks for people and name
return people.stream()
.filter(p -> p.getName().equals(name))
.filter(p -> p.getAge().get() >= age.orElse(0))
.collect(Collectors.toList());
}
// Optional Argument에 Null 들어가면 NullPointerException 발생!!!
someObject.search(people, "Peter", null);
위 Method를 아래와 같이 2가지 방법으로 개선하는 게 좋다.
1. Return으로 Optional 활용
public static List<Person> search(List<Person> people, String name, Integer age) {
// Null checks for people and name
final Integer ageFilter = age != null ? age : 0;
return people.stream()
.filter(p -> p.getName().equals(name))
.filter(p -> p.getAge().get() >= ageFilter)
.collect(Collectors.toList());
}
2. Overloading 활용
public static List<Person> search(List<Person> people, String name) {
return doSearch(people, name, 0);
}
public static List<Person> search(List<Person> people, String name, int age) {
return doSearch(people, name, age);
}
private static List<Person> doSearch(List<Person> people, String name, int age) {
// Null checks for people and name
return people.stream()
.filter(p -> p.getName().equals(name))
.filter(p -> p.getAge().get().intValue() >= age)
.collect(Collectors.toList());
}
Optional and Serialization
field Type으로 Optional를 활용하는 것 추천하지 않는다.
Serializtion 객체에 Optional field를 사용하면 NotSerializableException이 발생할 수 있다.
해당 사항은 따로 글을 작성하여 설명하려 한다.
[참고사이트]
'Programing > Java' 카테고리의 다른 글
JVM (0) | 2021.11.27 |
---|---|
Serialization (0) | 2021.11.20 |
Log4j vs Logback (0) | 2021.10.26 |
Interface vs Abstract (0) | 2021.10.21 |
Generic (0) | 2021.10.15 |