๐ฆ chap11. null ๋์ Optional ํด๋์ค
chap11. null ๋์ Optioanl ํด๋์ค
11.1 ๊ฐ์ด ์๋ ์ํฉ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ๊น?
11.1.1 ๋ณด์์ ์ธ ์์ธ๋ก NullPointerException ์ค์ด๊ธฐ
- ๊น์ ์์ฌ
1
2
3
4
5
6
7
8
9
10
11
12
public String getCarInsuranceName(Person person) {
if (person != null) {
Car car = person.getCar();
if (car != null) {
Insurance insurance = car.getInsurancee();
if (insurance != null) {
return insurance.getName();
}
}
}
return "Unknown";
}
null ํ์ธ ์ฝ๋ ๋๋ฌธ์ ๋๋จธ์ง ํธ์ถ ์ฒด์ธ์ ๋ค์ฌ์ฐ๊ธฐ ์์ค์ด ์ฆ๊ฐํ๋ค.
- ๋๋ฌด ๋ง์ ์ถ๊ตฌ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public String getCarInsuranceName(Person person) {
if (person == null) {
return "Unknown";
}
Car car = person.getCar();
if (car == null) {
return "Unknown";
}
Insurance insurance = car.getInsurance();
if (insurance == null) {
return "Unknown";
}
return insurance.getName();
}
๋ฐ๋ณต ํจํด ์ฝ๋๋ก ์ฝ๋์ ๊ตฌ์กฐ๊ฐ ์๋ง์ด ๋๊ณ ๊ฐ๋ ์ฑ๋ ๋จ์ด์ง๋ค
11.1.2 null ๋๋ฌธ์ ๋ฐ์ํ๋ ๋ฌธ์
- ์๋ฌ์ ๊ทผ์
- ์ฝ๋๋ฅผ ์ด์ง๋ฝํ๋ค
- ์๋ฌด ์๋ฏธ๊ฐ ์๋ค
- ์๋ฐ ์ฒ ํ์ ์๋ฐฐ๋๋ค
- ํ์ ์์คํ ์ ๊ตฌ๋ฉ์ ๋ง๋ ๋ค
11.1.3 ๋ค๋ฅธ ์ธ์ด๋ null ๋์ ์ ๋ฌด์ผ ์ฌ์ฉํ๋?
- ์์ ๋ด๋น๊ฒ์ด์ ์ฐ์ฐ์ (?.)
1
def carInsuranceName = parson?.car?.insurance?.name
- Maybe
- Option[T]
11.2 Optional ํด๋์ค ์๊ฐ
์๋ฐ 8์ ํ์ค์ผ๊ณผ ์ค์นผ๋ผ์ ์ํฅ์ ๋ฐ์ java.util.Optional
์ด๋ ์ ํํ ๊ฐ์ ์บก์ํํ๋ ํด๋์ค์ด๋ค.
null ์ ์ฐธ์กฐํ๋ ค ํ๋ฉด NPE ๊ฐ ๋ฐ์ํ์ง๋ง Optional.empty() ๋ ๊ฐ์ฒด์ด๋ฏ๋ก ๋ค์ํ๊ฒ ํ ์ฉํ ์ ์๋ค
๋ํ null ๋์ Optional ์ ์ฌ์ฉํ๋ฉด์ ํ์์ด Optional
์ด๋ ๊ฐ์ด ์์ ์ ์์์ ๋ช ์์ ์ผ๋ก ๋ณด์ฌ์ค ์ ์๋ค
11.3 Optional ์ ์ฉ ํจํด
11.3.1 Optional ๊ฐ์ฒด ๋ง๋ค๊ธฐ
- ๋น Optional
1
Optional<Car> optCar = Optional.empty();
- null์ด ์๋ ๊ฐ์ผ๋ก Optional ๋ง๋ค๊ธฐ
1
Optional<Car> optCar = Optional.of(car);
- null๊ฐ์ผ๋ก Optional ๋ง๋ค๊ธฐ
1
Optional<Car> optCar = Optional.ofNullable(car);
11.3.2 ๋งต์ผ๋ก Optional์ ๊ฐ์ ์ถ์ถํ๊ณ ๋ณํํ๊ธฐ
Optional ์ map ๋ฉ์๋๋ ์คํธ๋ฆผ์ map ๋ฉ์๋์ ๋น์ทํ๋ค
Optional ๊ฐ์ฒด๋ฅผ ์ต๋ ์์์ ๊ฐ์๊ฐ ํ ๊ฐ ์ดํ์ธ ๋ฐ์ดํฐ ์ปฌ๋ ์ ์ผ๋ก ์๊ฐํ๊ณ
๊ฐ์ ํฌํจํ๋ฉด map ์ ์ธ์๋ก ์ ๊ณต๋ ํจ์๊ฐ ๊ฐ์ ๋ฐ๊พผ๋ค
1
2
Optional<Insurance> optInsurance = Optional.ofNullable(insurance);
Optional<String> name = optInsurance.map(Insurance::getName);
11.3.3 flatMap ์ผ๋ก Optional ๊ฐ์ฒด ์ฐ๊ฒฐ
์ด์ฐจ์ Optional ์ flatMap ์ผ๋ก ์ผ์ฐจ์ Optional ๋ก ์ฐ๊ฒฐํ ์ ์๋ค
- Optional ๋ก ์๋์ฐจ์ ๋ณดํํ์ฌ ์ด๋ฆ ์ฐพ๊ธฐ
1
2
3
4
5
6
public String getCarInsuranceName(Optional<Person> person) {
return person.flatMap(Person::getCar)
.flatMap(Car::Insurance)
.map(Insurance::getName)
.orElse("Unknown");
}
null ์ ํ์ธํ๋๋ผ ์กฐ๊ฑด ๋ถ๊ธฐ๋ฌธ์ ์ถ๊ฐํด์ ์ฝ๋๋ฅผ ๋ณต์กํ๊ฒ ๋ง๋ค์ง ์์ผ๋ฉด์๋ ์ฝ๊ฒ ์ดํดํ ์ ์๋ ์ฝ๋๋ฅผ ์์ฑํ๋ค.
๋ ๋๋ฉ์ธ ๋ชจ๋ธ๊ณผ ๊ด๋ จํ ์๋ฌต์ ์ธ ์ง์์ ์์กดํ์ง ์๊ณ ๋ช ์์ ์ผ๋ก ํ์ ์์คํ ์ ์ ์ํ ์ ์๋ค.
11.3.4 Optional ์คํธ๋ฆผ ์กฐ์
์๋ฐ 9์์๋ Optional ์ stream() ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๋ค.
1
2
3
4
5
6
7
8
public Set<String> getCarInsuranceNames(List<Person> persons) {
return persons.stream()
.map(Person::getCar)
.map(optCar -> optCar.flatMap(Car::getInsurance))
.map(optIns -> optIns.map(Insurance::getName))
.flatMap(Optional::stream)
.collect(toSet());
}
Optional ๋๋ถ์ ์ฌ๋ฌ ์ฐ์ฐ์ null ๊ฑฑ์ ์์ด ์์ ํ๊ฒ ์ฒ๋ฆฌํ ์ ์์ง๋ง ๋ง์ง๋ง ๊ฒฐ๊ณผ๋ฅผ ์ป๊ธฐ ์ํด ๋น Optional ์ ์ ๊ฑฐํ๊ณ ๊ฐ์ ์ธ๋ฉํด์ผ ํ๋ค.
1
2
3
4
Stream<Optional<String>> stream =
Set<String> result = stream.filter(Optional::isPresent)
.map(Optional::get)
.collect(toSet());
filter ์ map ์ ์ด์ฉํด 0๊ฐ ์ด์์ ํญ๋ชฉ์ ํฌํจํ๋ ์คํธ๋ฆผ์ผ๋ก ๋ณํํ์ฌ ๊ฐ์ ํฌํจํ๋ Optional ์ ์ธ๋ฉํ๊ณ ๋น์ด์๋ Optional ์ ๊ฑด๋๋ธ ์ ์๋ค
11.3.5 ๋ํดํธ ์ก์ ๊ณผ Optional ์ธ๋ฉ
- get() : ๋ํ๋ ๊ฐ์ด ์์ผ๋ฉด NoSuchElementException ์ ๋ฐ์์ํค๊ธฐ ๋๋ฌธ์ ๊ฐ์ฅ ์์ ํ์ง ์๊ณ ์ฌ์ฉํ์ง ์๋ ๊ฒ์ด ๋ฐ๋์งํ๋ค.
- orElse: ๊ฐ์ ํฌํจํ์ง ์์ ๋ ๊ธฐ๋ณธ๊ฐ์ ์ ๊ณตํ ์ ์๋ค.
- orElseGet(Supplier<? extends T> other) : Optional ์ ๊ฐ์ด ์์ ๋๋ง Supplier ๊ฐ ์คํ๋๋ค.
- orElseThrow(Supplier<? extends X> exceptionSupplier) : Optional ์ด ๋น์ด์์ ๋ ์์ธ๋ฅผ ๋ฐ์์ํจ๋ค.
- ifPresent(Consumer<? super T> consumer : ๊ฐ์ด ์กด์ฌํ ๋ ์ธ์๋ก ๋๊ฒจ์ค ๋์์ ์คํํ๋ค
์๋ฐ 9์์๋ ์ธ์คํด์ค ๋ฉ์๋๊ฐ ์ถ๊ฐ๋์๋ค.
- ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) : Optional ์ด ๋น์ด์์ ๋ Runnable์ ์ธ์๋ก ๋ฐ์ ์คํํ๋ค.
11.3.6 ๋ Optional ํฉ์น๊ธฐ
1
2
3
4
public Optional<Insurance> nullSafeFindCheapestInsurance(
Optional<Person> person, Optional<Car> car) {
return person.flatMap(p -> car.map(c -> findCheapestInsurance(p, c));
}
11.3.7 ํํฐ๋ก ํน์ ๊ฐ ๊ฑฐ๋ฅด๊ธฐ
1
2
3
4
Optional<Insurance> optInsurance = ...;
optInsurance.filter(insurance ->
"CambridgeInsurance".equals(insurance.getName())
.ifPresent(x -> System.out.println("ok"));
11.4 Optional ์ ์ฌ์ฉํ ์ค์ฉ ์์
11.4.1 ์ ์ฌ์ ์ผ๋ก null์ด ๋ ์ ์๋ ๋์์ Optional๋ก ๊ฐ์ธ๊ธฐ
1
Optional<Object> value = Optional.ofNullable(map.get("key"));
11.4.2 ์์ธ์ Optional ํด๋์ค
Integer.parseInt(String) ์ ๋ฌธ์์ด์ ์ ์๋ก ๋ฐ๊พธ์ง ๋ชปํ ๋ NumberFormatException ์ ๋ฐ์์ํจ๋ค.
์ด๋ฅผ ๋น Optional ๋ก ํด๊ฒฐํ ์ ์๋ค.
1
2
3
4
5
6
7
public static Optional<Integer> stringToInt(String s) {
try {
return Optional.of(Integer.parseInt(s));
} catch (NumberFormatException e) {
return Optional.empty();
}
}
11.4.3 ๊ธฐ๋ณธํ Optional์ ์ฌ์ฉํ์ง ๋ง์์ผ ํ๋ ์ด์
OptionalInt, OptionalLong, OptionalDouble ๋ฑ์ ํด๋์ค๋ฅผ ์ ๊ณตํ๋ค.
Stream ๊ณผ๋ ๋ค๋ฅด๊ฒ Optional ์ ์ต๋ ์์๋ 1๊ฐ์ด๋ฏ๋ก ๊ธฐ๋ณธํ ํนํ ํด๋์ค๋ก ์ฑ๋ฅ์ ๊ฐ์ ํ ์๋ ์๋ค