๐ฃ chap11. null ๋์ Optional ํด๋์ค
๊ฐ์ด ์๋ ์ํฉ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ๊น?
๋ค์ ์ฝ๋์์๋ ์ด๋ค ๋ฌธ์ ๊ฐ ๋ฐ์ํ ๊น?
1
2
3
public String getCarInsuranceName(Person person) {
return person.getCar().getInsurance().getName();
}
์ฝ๋์์ ์๋์ฐจ๋ฅผ ์์ ํ์ง ์์ ์ฌ๋์ด๋ผ๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
์๋์ฐจ๋ ์์ ํ๊ณ ์์ง๋ง ๋ณดํ์ ๋ณด์ ํ๊ณ ์์ง ์๋ค๋ฉด?
โ NullPointerException์ด ๋ฐ์ํ ๊ฐ๋ฅ์ฑ
๋ณด์์ ์ธ ์์ธ๋ก NullPointerException ์ค์ด๊ธฐ
์๊ธฐ์น ์์ NullPointerException์ ํผํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น?
โ ๋๋ถ๋ถ์ ํ๋ก๊ทธ๋๋จธ๋ ํ์ํ ๊ณณ์ ๋ค์ํ null ํ์ธ ์ฝ๋๋ฅผ ์ถ๊ฐํด์ null ์์ธ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ฌ ํ ๊ฒ์ด๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public String getCarInsuranceName(Person person) {
if (person != null) {
Car car = person.getCar();
if (car != null) {
Insurance insurance = car.getInsurance();
if (insurance != null) {
return insurance.getName();
}
}
}
return "Unknown";
}
์ด์ ๊ฐ์ ๋ฐ๋ณต ํจํด ์ฝ๋๋ฅผ โ๊น์ ์์ฌ
โ์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
์ด๋ฅผ ๋ฐ๋ณตํ๋ค ๋ณด๋ฉด ์ฝ๋์ ๊ตฌ์กฐ๊ฐ ์๋ง์ด ๋๊ณ ๊ฐ๋
์ฑ๋ ๋จ์ด์ง๋ค.
โ ๋ญ๊ฐ ๋ค๋ฅธ ํด๊ฒฐ ๋ฐฉ๋ฒ์ด ํ์ํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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();
}
์ ์ฝ๋๋ ์กฐ๊ธ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก ์ค์ฒฉ if ๋ธ๋ก์ ์์ด๋ค.
null์ผ ๋ ๋ฐํ๋๋ ๊ธฐ๋ณธ๊ฐ โUnknownโ์ด ์ธ ๊ณณ์์ ๋ฐ๋ณต๋๊ณ ์๋๋ฐ ๊ฐ์ ๋ฌธ์์ด์ ๋ฐ๋ณตํ๋ฉด์ ์คํ ๋ฑ์ ์ค์๊ฐ ์๊ธธ ์ ์๋ค.
null ๋๋ฌธ์ ๋ฐ์ํ๋ ๋ฌธ์
- ์๋ฐ์์ null ๋ ํผ๋ฐ์ค๋ฅผ ์ฌ์ฉํ๋ฉด์ ๋ฐ์ํ ์ ์๋ ์ด๋ก ์ , ์ค์ฉ์ ๋ฌธ์
- ์๋ฌ์ ๊ทผ์์ด๋ค - NullPointerException์ ์๋ฐ์์ ๊ฐ์ฅ ํํ ๋ฐ์ํ๋ ์๋ฌ๋ค
- ์ฝ๋๋ฅผ ์ด์ง๋ฝํ๋ค : null ํ์ธ ์ฝ๋๋ฅผ ์ถ๊ฐํด์ผ ํ๋ฏ๋ก
๊ณผ๋ํ ์ฒดํฌ ๋ก์ง
์ผ๋ก ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง๋ค. - ์๋ฌด ์๋ฏธ๊ฐ ์๋ค : ์ ์ ํ์ ์ธ์ด์์ ๊ฐ์ด ์์์ ํํํ๋ ๋ฐฉ๋ฒ์ผ๋ก๋ ์ ์ ํ์ง ์๋ค.
- ์๋ฐ ์ฒ ํ์ ์๋ฐฐ
ํ์ ์์คํ ์ ๊ตฌ๋ฉ์ ๋ง๋ ๋ค.
Optional ํด๋์ค ์๊ฐ
Optional์ ์ ํํ๊ฐ์ ์บก์ํํ๋ ํด๋์ค๋ค.
๊ฐ์ด ์์ผ๋ฉด Optional ํด๋์ค๋ ๊ฐ์ ๊ฐ์ผ๋ค.
๋ฐ๋ฉด ๊ฐ์ด ์์ผ๋ฉด Optional.empty ๋ฉ์๋๋ก Optional์ ๋ฐํํ๋ค.
์๋ฏธ์์ผ๋ก ๋์ด ๋น์ทํ์ง๋ง ์ค์ ๋ก๋ ์ฐจ์ด์ ์ด ๋ง๋ค.
null์ ์ฐธ์กฐํ๋ ค ํ๋ฉด NullPointerException์ด ๋ฐ์ํ์ง๋ง Optional.empty()๋ Optional ๊ฐ์ฒด์ด๋ฏ๋ก ์ด๋ฅผ ๋ค์ํ ๋ฐฉ์์ผ๋ก ํ์ฉํ ์ ์๋ค.
Optional ์ ์ฉ ํจํด
๋น OptionalOptional.empty๋ก ๋น Optional ๊ฐ์ฒด๋ฅผ ์ป์ ์ ์๋ค. Optional
null์ด ์๋ ๊ฐ์ผ๋ก Optional ๋ง๋ค๊ธฐ Optional
null๊ฐ์ผ๋ก Optional ๋ง๋ค๊ธฐ Optional
๊ทธ๋ฐ๋ฐ Optional์ด ๋น์ด์์ผ๋ฉด get์ ํธ์ถํ์ ๋ ์์ธ๊ฐ ๋ฐ์ํ๋ค.
์ฆ, Optional์ ์๋ชป ์ฌ์ฉํ๋ฉด ๊ฒฐ๊ตญ null์ ์ฌ์ฉํ์ ๋์ ๊ฐ์ ๋ฌธ์ ๋ฅผ ๊ฒช์ ์ ์๋ค. ๋ฐ๋ผ์ Optional๋ก ๋ช ์์ ์ธ ๊ฒ์ฌ๋ฅผ ์ ๊ฑฐํ ์ ์๋ ๋ฐฉ๋ฒ์ ํ์ธํด์ผ ํ๋ค.
๋งต์ผ๋ก Optional์ ๊ฐ์ ์ถ์ถํ๊ณ ๋ณํํ๊ธฐ
๋ณดํต ๊ฐ์ฒด์ ์ ๋ณด๋ฅผ ์ถ์ถํ ๋๋ Optional์ ์ฌ์ฉํ ๋๊ฐ ๋ง๋ค.
1
2
3
4
5
String name = null;
if(insurance != null) {
name = insurance.getName();
}
์ด๋ฐ ์ ํ์ ํจํด์ ์ฌ์ฉํ ์ ์๋๋ก Optional์ map ๋ฉ์๋๋ฅผ ์ง์ํ๋ค.
Optional
Optional
Optional์ด ๊ฐ์ ํฌํจํ๋ฉด map์ ์ธ์๋ก ์ ๊ณต๋ ํจ์๊ฐ ๊ฐ์ ๋ฐ๊พผ๋ค.
optional์ด ๋น์ด ์์ผ๋ฉด ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์๋๋ค.
flatMap์ผ๋ก Optional ๊ฐ์ฒด ์ฐ๊ฒฐ
1
2
3
4
5
Optional<Person> optPerson = Optional.of(person);
Optional<String> name = optPerson.map(Person::getCar)
.map(Car::getInsurance)
.map(Insurance::getName);
์ํ๊น๊ฒ๋ ์ ์ฝ๋๋ ์ปดํ์ผ๋์ง ์๋๋ค.
๋ณ์ optPeople์ ํ์์ Optional์ด๋ฏ๋ก map ๋ฉ์๋๋ฅผ ํธ์ถํ ์ ์๋ค. ํ์ง๋ง ๊ทธ ๋ค์ ์ฐ์ฐ์ Optional> ํ์์ ๊ฐ์ฒด์ด๋ฏ๋ก getInsurance ๋ฉ์๋๋ฅผ ์ง์ํ์ง ์๋๋ค.
์คํธ๋ฆผ์ flatMap
์ ํจ์๋ฅผ ์ธ์๋ก ๋ฐ์์ ๋ค๋ฅธ ์คํธ๋ฆผ์ ๋ฐํํ๋ ๋ฉ์๋๋ค. ์ฆ flatMap์ ์ธ์๋ก ๋ฐ์ ํจ์๋ฅผ ์ ์ฉํด์ ์์ฑ๋ ๊ฐ๊ฐ์ ์คํธ๋ฆผ์์ ์ฝํ
์ธ ๋ง ๋จ๊ธฐ๊ฒ ๋๋ฏ๋ก ์์ ๊ฐ์ ์ด์๋ฅผ ํด๊ฒฐํ ์ ์๋ค.
1
2
3
4
5
6
Optional<Person> optPerson = Optional.of(person);
Optional<String> name = optPerson.flatMap(Person::getCar)
.flatMap(Car::getInsurance)
.map(Insurance::getName)
.orElse("Unknown");
๋ํดํธ ์ก์ ๊ณผ Optional ์ธ๋ฉ
Optional ํด๋์ค๋ Optional ์ธ์คํด์ค์์ ๊ฐ์ ์ฝ์ ์ ์๋ ๋ค์ํ ์ธ์คํด์ค ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค.
get() : ๋ํ๋ ๊ฐ์ด ์์ผ๋ฉด ํด๋น ๊ฐ์ ๋ฐํํ๊ณ ๊ฐ์ด ์์ผ๋ฉด NoSuchElementException์ ๋ฐ์์ํจ๋ค.
orElse(T other) : Optional์ด ๊ฐ์ ํฌํจํ์ง ์์ ๋ ๋ํดํธ๊ฐ์ ์ ๊ณตํ ์ ์๋ค.
orElseGet(Supplier<? extends T> other) : orElse ๋ฉ์๋์ ๋์ํ๋ ๊ฒ์ผ๋ฅธ ๋ฒ์ ์ ๋ฉ์๋
๋ค. Optional์ ๊ฐ์ด ์์ ๋๋ง Supplier๊ฐ ์คํ๋๊ธฐ ๋๋ฌธ์ด๋ค.
orElseThrow(Supplier<? extends T> exceptionSupplier) : Optional์ด ๋น์ด์์๋ ์์ธ๋ฅผ ๋ฐ์์ํจ๋ค๋ ์ ์์ get ๋ฉ์๋์ ๋น์ทํ๋ค
ifPresent(Consumer<? super T> consumer) : ๊ฐ์ด ์กด์ฌํ ๋ ์ธ์๋ก ๋๊ฒจ์ค ๋์์ ์คํํ ์ ์๋ค.
๊ฐ์ด ์์ผ๋ฉด ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์๋๋ค.
๋ Optional ํฉ์น๊ธฐ
์ด์ Person๊ณผ Car ์ ๋ณด๋ฅผ ์ด์ฉํด์ ๊ฐ์ฅ ์ ๋ ดํ ๋ณด๋ผ๋ฃ๋ฅผ ์ ๊ณตํ๋ ๋ณดํํ์ฌ๋ฅผ ์ฐพ๋ ๊ธฐ๋ฅ์ ๊ตฌํ
1
2
3
4
5
6
7
8
9
public Optional<Insurance> nullSafeFindCheapestInsurance(
Optional<Person> person, Optional<Car> car) {
if (person.isPresent() && car.isPersent()) {
return Optional.of(findCheapestInsurance(person.get(), car.get());
} else {
return Optional.empty();
}
}
}
๊ตฌํ ์ฝ๋๋ null ํ์ธ ์ฝ๋์ ํฌ๊ฒ ๋ค๋ฅธ์ ์ด ์๋ค.
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));
}
์ฒซ ๋ฒ์งธ Optional์ flatMap์ ํธ์ถํ์ผ๋ฏ๋ก ์ฒซ ๋ฒ์งธ Optional์ด ๋น์ด์๋ค๋ฉด ์ธ์๋ก ์ ๋ฌํ ๋๋ค ํํ์์ด ์คํ๋์ง ์๊ณ ๊ทธ๋๋ก ๋น Optional์ ๋ฐํํ๋ค.
ํํฐ๋ก ํน์ ๊ฐ ๊ฑฐ๋ฅด๊ธฐ
์ข ์ข ๊ฐ์ฒด์ ๋ฉ์๋๋ฅผ ํธ์ถํด์ ์ด๋ค ํ๋กํผํฐ๋ฅผ ํ์ธํด์ผ ํ ๋๊ฐ ์๋ค. ์๋ฅผ ๋ค์ด ๋ณดํํ์ฌ ์ด๋ฆ์ด โCambridgeInsuranceโ์ธ์ง ํ์ธํด์ผ ํ๋ค๊ณ ๊ฐ์ ํ์
1
2
3
4
5
Insurance insurance = ...;
if(insurance != null && "CambridgeInsurance".equals(insurance.getName())) {
System.out.println("ok");
}
Optional ๊ฐ์ฒด์ filter ๋ฉ์๋๋ฅผ ์ด์ฉํด์ ๋ค์๊ณผ ๊ฐ์ด ์ฝ๋๋ฅผ ์ฌ๊ตฌํํ ์ ์๋ค.
1
2
3
Optional<Insurance> optInsurance = ...;
optInsurance.filter(insurance -> "CambridgeInsurance".equals(insurance.getName())).ifPresent(x -> System.out.println("ok"));
Optional์ด ๋น์ด์๋ค๋ฉด filter ์ฐ์ฐ์ ์๋ฌด๋์๋ ํ์ง ์๋๋ค.
์์ธ์ Optional
Integer.parseInt(String)์ ์ ์ ๋ฉ์๋
์ด ๋ฉ์๋๋ ๋ฌธ์์ด์ ์ ์๋ก ๋ฐ๊พธ์ง ๋ชปํ ๋ NumberFormatException
์ ๋ฐ์
์ฆ, ๋ฌธ์์ด์ด ์ซ์๊ฐ ์๋๋ผ๋ ์ฌ์ค์ ์์ธ๋ก ์๋ฆฌ๋ ๊ฒ์ด๋ค.
๊ธฐ์กด์ ๊ฐ์ด null์ผ ์ ์์ ๋๋ if ๋ฌธ์ผ๋ก null ์ฌ๋ถ๋ฅผ ํ์ธํ์ง๋ง ์์ธ๋ฅผ ๋ฐ์์ํค๋ ๋ฉ์๋์์๋ try/catch ๋ธ๋ก์ ์ฌ์ฉํด์ผ ํ๋ค๋ ์ ์ด ๋ค๋ฅด๋ค.
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();
}
}
๊ธฐ์กด ์๋ฐ ๋ฉ์๋ parseInt๋ฅผ ์ง์ ๊ณ ์น ์๋ ์์ง๋ง ๋ค๋ฆ ์ฝ๋์ฒ๋ผ parseInt๋ฅผ ๊ฐ์ธ๋ ์์ ์ ํธ๋ฆฌํฐ ๋ฉ์๋
๋ฅผ ๊ตฌํํด์ Optional์ ๋ฐํํ ์ ์๋ค.