๐น chap11. null ๋์ Optional ํด๋์ค
11.1 ๊ฐ์ด ์๋ ์ํฉ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ๊น?
๋ค์์ฒ๋ผ ์๋์ฐจ์ ์๋์ฐจ ๋ณดํ์ ๊ฐ๊ณ ์๋ ์ฌ๋ ๊ฐ์ฒด๋ฅผ ์ค์ฒฉ ๊ตฌ์กฐ๋ก ๊ตฌํํ๋ค๊ณ ํ์.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Person/Car/Insurance ๋ฐ์ดํฐ ๋ชจ๋ธ
public class Person {
private Car car;
public Car getCar() { return car; }
}
public class Car {
private Insurance insurance;
public Insurance getInsurance() { return insurance; }
}
public class Insurance {
private String name;
public String getName() { return name; }
}
1
2
3
public String getCarInsuranceName(Person person) {
return person.getCar().getInsurance().getName();
}
์ ์ฝ๋๋ ์๋ฌด ๋ฌธ์ ๊ฐ ์๋ ๊ฒ์ฒ๋ผ ๋ณด์ด์ง๋ง ์ฐจ๋ฅผ ์์ ํ์ง ์์ ์ฌ๋๋ ๋ง๋ค. ์ด๋ getCar์ ํธ์ถํ๋ฉด null ์ฐธ์กฐ๋ฅผ ๋ฐํํ๋ ๋ฐฉ์์ผ๋ก ์๋์ฐจ๋ฅผ ์์ ํ๊ณ ์์ง ์์์ ํํํ ๊ฒ์ด๋ค. ๊ทธ๋ฌ๋ฉด getInsurance๋ null ์ฐธ์กฐ์ ๋ณดํ ์ ๋ณด๋ฅผ ๋ฐํํ๋ ค ํ ๊ฒ์ด๋ฏ๋ก ๋ฐํ์์ NullPointerException์ด ๋ฐ์ํ๋ฉด์ ํ๋ก๊ทธ๋๋ฐ ์ค๋จ๋๋ค.
person์ด null์ด๊ฑฐ๋ getInsurance๊ฐ null์ ๋ฐํํ ์๋ ์๋ค.
11.1.1 ๋ณด์์ ์ธ ์์ธ๋ก NullPointerException ์ค์ด๊ธฐ
๋ณด์์ ์ธ ๋ฐฉ๋ฒ์ผ๋ก ๋ค์ํ null ํ์ธ ์ฝ๋๋ฅผ ์ถ๊ฐํ์ฌ null ์์ธ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// null ์์ ์๋ 1: ๊น์ ์์ฌ
public String getCarInsuranceName(Person person) {
if (person != null) {
Car car = person.getCar();
if (car != null) {
Insurance insurance = car.getInsurancee();
if (insurance != null) {
// null ํ์ธ ์ฝ๋ ๋๋ฌธ์ ๋๋จธ์ง ํธ์ถ ์ฒด์ธ์ ๋ค์ฌ์ฐ๊ธฐ ์์ค์ด ์ฆ๊ฐํ๋ค.
return insurance.getName();
}
}
}
return "Unknown";
}
์ ์ฝ๋์์๋ ๋ณ์๋ฅผ ์ฐธ์กฐํ ๋๋ง๋ค null์ ํ์ธํ๋ฉฐ ์ค๊ฐ ๊ณผ์ ์ ํ๋๋ผ๋ null ์ฐธ์กฐ๊ฐ ์์ผ๋ฉด โUnknownโ์ด๋ผ๋ ๋ฌธ์์ด์ ๋ฐํํ๋ค.
๋ฉ์๋์์๋ ๋ชจ๋ ๋ณ์๊ฐ null์ธ์ง ์์ฌํ๋ฏ๋ก ๋ณ์๋ฅผ ์ ๊ทผํ ๋๋ง๋ค ์ค์ฒฉ๋ if๊ฐ ์ถ๊ฐ๋๋ฉด์ ์ฝ๋ ๋ค์ฌ์ฐ๊ธฐ ์์ค์ด ์ฆ๊ฐํ๋ค. ์ด๋ฅผ ๋ฐ๋ณตํ๋ค๋ณด๋ฉด ์ฝ๋์ ๊ตฌ์กฐ๊ฐ ์๋ง์ด ๋๊ณ ๊ฐ๋ ์ฑ๋ ๋จ์ด์ง๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// null ์์ ์๋ 2: ๋๋ฌด ๋ง์ ์ถ๊ตฌ
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();
}
์ ์ฝ๋๋ null ๋ณ์๊ฐ ์์ผ๋ฉด ์ฆ์ โUnknownโ์ ๋ฐํํ๋ค. ํ์ง๋ง ๋ฉ์๋์ ๋ค ๊ฐ์ ์ถ๊ตฌ๊ฐ ์๊ฒผ๊ธฐ ๋๋ฌธ์ ์ ์ง๋ณด์๊ฐ ์ด๋ ค์์ง๋ค.
๊ฒ๋ค๊ฐ โUnknownโ์ด ์ธ ๊ณณ์์ ๋ฐ๋ณต๋๊ณ ์๋๋ฐ ๊ฐ์ ๋ฌธ์์ด์ ๋ฐ๋ณตํ๋ฉด์ ์คํ ๋ฑ์ ์ค์๊ฐ ์๊ธธ ์ ์๋ค.
11.1.2 null ๋๋ฌธ์ ๋ฐ์ํ๋ ๋ฌธ์
null ์ฐธ์กฐ๋ฅผ ์ฌ์ฉํ๋ฉด์ ๋ฐ์ํ ์ ์๋ ์ด๋ก ์ , ์ค์ฉ์ ๋ฌธ์ ๋ ๋ค์๊ณผ ๊ฐ๋ค.
์๋ฌ์ ๊ทผ์์ด๋ค
: NullPointerException์ ์๋ฐ์์ ๊ฐ์ฅ ํํ ๋ฐ์ํ๋ ์๋ฌ๋ค.
์ฝ๋๋ฅผ ์ด์ง๋ฝํ๋ค
: ๋๋ก๋ ์ค์ฒฉ๋ null ํ์ธ ์ฝ๋๋ฅผ ์ถ๊ฐํด์ผ ํ๋ฏ๋ก null ๋๋ฌธ์ ์ฝ๋ ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง๋ค.
์๋ฌด ์๋ฏธ๊ฐ ์๋ค
: null์ ์๋ฌด ์๋ฏธ๋ ํํํ์ง ์๋๋ค. ํนํ ์ ์ ํ์ ์ธ์ด์์ ๊ฐ์ด ์์์ ํํํ๋ ๋ฐฉ๋ฒ์ผ๋ก๋ ์ ์ ํ์ง ์๋ค.
์๋ฐ ์ฒ ํ์ ์๋ฐฐ๋๋ค
: ์๋ฐ๋ ๊ฐ๋ฐ์๋ก๋ถํฐ ๋ชจ๋ ํฌ์ธํฐ๋ฅผ ์จ๊ฒผ๋ค. ํ์ง๋ง ์์ธ๊ฐ ์๋๋ฐ ๊ทธ๊ฒ์ด ๋ฐ๋ก null ํฌ์ธํฐ๋ค.
ํ์ ์์คํ ์ ๊ตฌ๋ฉ์ ๋ง๋ ๋ค
: null์ ๋ฌดํ์์ด๋ฉฐ ์ ๋ณด๋ฅผ ํฌํจํ๊ณ ์์ง ์์ผ๋ฏ๋ก ๋ชจ๋ ์ฐธ์กฐ ํ์์ null์ ํ ๋นํ ์ ์๋ค. ์ด๋ฐ ์์ผ๋ก null์ด ํ ๋น๋๊ธฐ ์์ํ๋ฉด์ ์์คํ ์ ๋ค๋ฅธ ๋ถ๋ถ์ผ๋ก null์ด ํผ์ก์ ๋ ์ ์ด์ null์ด ์ด๋ค ์๋ฏธ๋ก ์ฌ์ฉ๋์๋์ง ์ ์ ์๋ค.
11.1.3 ๋ค๋ฅธ ์ธ์ด๋ null ๋์ ๋ฌด์ผ ์ฌ์ฉํ๋?
๊ทธ๋ฃจ๋น
์ต๊ทผ ๊ทธ๋ฃจ๋น ๊ฐ์ ์ธ์ด์์๋ ์์ ๋ด๋น๊ฒ์ด์ ์ฐ์ฐ์ (?.)๋ฅผ ๋์ ํด์ null ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ค. ๋ค์์ ์ฌ๋๋ค์ด ๊ทธ๋ค์ ์๋์ฐจ์ ์ ์ฉํ ๋ณดํํ์ฌ์ ์ด๋ฆ์ ๊ฐ์ ธ์ค๋ ๊ทธ๋ฃจ๋น ์ฝ๋ ์์ ๋ค.
1
def carInsuranceName = person?.car?.insurance?.name
์ด๋ค ์ฌ๋์ ์๋์ฐจ๋ฅผ ๊ฐ์ง๊ณ ์์ง ์์ ์ ์์ผ๋ฉฐ ๋ฐ๋ผ์ Person ๊ฐ์ฒด์ car ์ฐธ์กฐ๋ null์ด ํ ๋น๋์ด ์์ ์ ์๋ค. ๊ทธ๋ฃจ๋น ์์ ๋ด๋น๊ฒ์ด์ ์ฐ์ฐ์๋ฅผ ์ด์ฉํ๋ฉด null ์ฐธ์กฐ ์์ธ ๊ฑฑ์ ์์ด ๊ฐ์ฒด์ ์ ๊ทผํ ์ ์๋ค. ์ด๋ ํธ์ถ ์ฒด์ธ์ null์ธ ์ฐธ์กฐ๊ฐ ์์ผ๋ฉด ๊ฒฐ๊ณผ๋ก null์ด ๋ฐํ๋๋ค.
ํ์ค์ผ, ์ค์นผ๋ผ
ํ์ค์ผ, ์ค์นผ๋ผ ๋ฑ์ ํจ์ํ ์ธ์ด๋ ์์ ๋ค๋ฅธ ๊ด์ ์์ null ๋ฌธ์ ๋ฅผ ์ ๊ทผํ๋ค.
- Maybe(ํ์ค์ผ)
- ์ ํํ ๊ฐ์ ์ ์ฅ
- ์ฃผ์ด์ง ํ์์ ๊ฐ์ ๊ฐ๊ฑฐ๋ ์๋๋ฉด ์๋ฌด ๊ฐ๋ ๊ฐ์ง ์์ ์ ์๋ค. ๋ฐ๋ผ์ null ์ฐธ์กฐ ๊ฐ๋ ์ ์์ฐ์ค๋ฝ๊ฒ ์ฌ๋ผ์ง๋ค.
- Option[T](์ค์นผ๋ผ)
- Tํ์์ ๊ฐ์ ๊ฐ๊ฑฐ๋ ์๋ฌด ๊ฐ๋ ๊ฐ์ง ์์ ์ ์๋ ๊ตฌ์กฐ
- Option ํ์์์ ์ ๊ณตํ๋ ์ฐ์ฐ์ ์ฌ์ฉํ์ฌ ๊ฐ์ด ์๋์ง ์ฌ๋ถ๋ฅผ ๋ช ์์ ์ผ๋ก ํ์ธํด์ผ ํ๋ค. โ ํ์ ์์คํ ์์ ์ด๋ฅผ ๊ฐ์ ํ๋ฏ๋ก null๊ณผ ๊ด๋ จํ ๋ฌธ์ ๊ฐ ์ผ์ด๋ ๊ฐ๋ฅ์ฑ์ด ์ค์ด๋ ๋ค.
11.2 Optional ํด๋์ค ์๊ฐ
์๋ฐ 8์ ํ์ค์ผ๊ณผ ์ค์นผ๋ผ์ ์ํฅ์ ๋ฐ์ **java.util.Optional
์๋ฅผ ๋ค์ด ์ด๋ค ์ฌ๋์ด ์ฐจ๋ฅผ ์์ ํ๊ณ ์์ง ์๋ค๋ฉด Person ํด๋์ค์ car ๋ณ์๋ null์ ๊ฐ์ ธ์ผ ํ ๊ฒ์ด๋ค. ํ์ง๋ง ์๋ก์ด Optional์ ์ด์ฉํ ์ ์์ผ๋ฏ๋ก null์ ํ ๋นํ๋ ๊ฒ์ด ์๋๋ผ **๋ณ์ํ์ Optional
๊ฐ์ด ์์ผ๋ฉด Oprional ํด๋์ค๋ ๊ฐ์ ๊ฐ์ผ๋ค. ๋ฐ๋ฉด ๊ฐ์ด ์์ผ๋ฉด Optional.empty ๋ฉ์๋๋ก Optional์ ๋ฐํํ๋ค. Optional.empty๋ Optional์ ํน๋ณํ ์ฑ๊ธํด ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋ ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋๋ค.
- null๊ณผ Optional.empty()์ ์ฐจ์ด
null
โ NullPointerException์ด ๋ฐ์Optional.empty()
โ Optional ๊ฐ์ฒด์ด๋ฏ๋ก ๋ค์ํ ๋ฐฉ์์ผ๋ก ํ์ฉ ๊ฐ๋ฅ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Optional๋ก Person/Car/Insurance ๋ฐ์ดํฐ ๋ชจ๋ธ ์ฌ์ ์
public class Person {
// ์ฌ๋์ด ์ฐจ๋ฅผ ์์ ํ์ ์๋ ์์ ํ์ง ์์์ ์๋ ์์ผ๋ฏ๋ก Optional๋ก ์ ์
private Optional<Car> car;
public Optional<Car> getCar() { return car; }
}
public class Car {
// ์๋์ฐจ๊ฐ ๋ณดํ์ ๊ฐ์
๋์ด ์์ ์๋ ๊ฐ์
๋์ด ์์ง ์์์๋ ์์ผ๋ฏ๋ก Optional๋ก ์ ์
private Optional<Insurance> insurance;
public Optional<Insurance> getInsurance() {
return insurance;
}
}
public class Insurance {
// ๋ณดํํ์ฌ์๋ ๋ฐ๋์ ์ด๋ฆ์ด ์๋ค.
private String name;
public String getName() {
return name;
}
}
Optional ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ฉด์ ๋ชจ๋ธ์ ์๋ฏธ๊ฐ ๋ ๋ช ํํด์ก๋ค.
Optional์ ์ด์ฉํ๋ฉด ๊ฐ์ด ์๋ ์ํฉ์ด ์ฐ๋ฆฌ ๋ฐ์ดํฐ์ ๋ฌธ์ ๊ฐ ์๋ ๊ฒ์ธ์ง ์๋๋ฉด ์๊ณ ๋ฆฌ์ฆ์ ๋ฒ๊ทธ์ธ์ง ๋ช ํํ๊ฒ ๊ตฌ๋ถํ ์ ์๋ค. ๋ชจ๋ null ์ฐธ์กฐ๋ฅผ Optional๋ก ๋์นํ๋ ๊ฒ์ ๋ฐ๋์งํ์ง ์๋ค. Optional์ ์ญํ ์ ๋ ์ดํดํ๊ธฐ ์ฌ์ด API๋ฅผ ์ค๊ณํ๋๋ก ๋๋ ๊ฒ์ด๋ค.
์ฆ, ๋ฉ์๋์ ์๊ทธ๋์ฒ๋ง ๋ณด๊ณ ๋ ์ ํํ๊ฐ์ธ์ง ์ฌ๋ถ๋ฅผ ๊ตฌ๋ณํ ์ ์๋ค. Optional์ด ๋ฑ์ฅํ๋ฉด ์ด๋ฅผ ์ธ๋ฉํด์ ๊ฐ์ด ์์ ์ ์๋ ์ํฉ์ ์ ์ ํ๊ฒ ๋์ํ๋๋ก ๊ฐ์ ํ๋ ํจ๊ณผ๊ฐ ์๋ค.
11.3 Optional ์ ์ฉ ํจํด
11.3.1 Optional ๊ฐ์ฒด ๋ง๋ค๊ธฐ
Optional์ ์ฌ์ฉํ๋ ค๋ฉด Optional ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ผ ํ๋ค. ๋ค์ํ ๋ฐฉ๋ฒ์ผ๋ก Optional ๊ฐ์ฒด๋ฅผ ๋ง๋ค ์ ์๋ค.
๋น Optional
์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋ Optional.empty
๋ก ๋น Optional ๊ฐ์ฒด๋ฅผ ์ป์ ์ ์๋ค.
1
Optional<Car> optCar = Optional.empty();
null์ด ์๋ ๊ฐ์ผ๋ก Optional ๋ง๋ค๊ธฐ
์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋ Optional.of
๋ก null์ด ์๋ ๊ฐ์ ํฌํจํ๋ Optional์ ๋ง๋ค ์ ์๋ค.
1
Optional<Car> optCar = Optional.of(car);
์ด์ car์ null์ด๋ผ๋ฉด ์ฆ์ NullPointerException์ด ๋ฐ์ํ๋ค(Optional์ ์ฌ์ฉํ์ง ์์๋ค๋ฉด car์ ํ๋กํผํฐ์ ์ ๊ทผํ๋ ค ํ ๋ ์๋ฌ๊ฐ ๋ฐ์ํ์ ๊ฒ์ด๋ค).
null๊ฐ์ผ๋ก Optional ๋ง๋ค๊ธฐ
์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋ Optional.ofNullable
๋ก null๊ฐ์ ์ ์ฅํ ์ ์๋ Optional์ ๋ง๋ค ์ ์๋ค.
1
Optional<Car> optCar = Optional.ofNullable(car);
car๊ฐ null์ด๋ฉด ๋น Optional ๊ฐ์ฒด๊ฐ ๋ฐํ๋๋ค.
11.3.2 ๋งต์ผ๋ก Optional์ ๊ฐ์ ์ถ์ถํ๊ณ ๋ณํํ๊ธฐ
๋ณดํต ๊ฐ์ฒด์ ์ ๋ณด๋ฅผ ์ถ์ถํ ๋๋ Optional์ ์ฌ์ฉํ ๋๊ฐ ๋ง๋ค.
์๋ฅผ ๋ค์ด ๋ณดํํ์ฌ์ ์ด๋ฆ์ ์ถ์ถํ ๋, ์ด๋ฆ ์ ๋ณด์ ์ ๊ทผํ๊ธฐ ์ ์ insurance๊ฐ null์ธ์ง ํ์ธํด์ผ ํ๋ค.
1
2
3
4
String name = null;
if (insurance != null) {
name = insurance.getName();
}
์ด๋ฐ ์ ํ์ ํจํด์ ์ฌ์ฉํ ์ ์๋๋ก Optional์ map ๋ฉ์๋๋ฅผ ์ง์ํ๋ค.
1
2
Optional<Insurance> optInsurance = Optional.ofNullable(insurance);
Optional<String> name = optInsurance.map(Insurance::getName);
Optional์ map ๋ฉ์๋๋ ์คํธ๋ฆผ์ map ๋ฉ์๋์ ๊ฐ๋ ์ ์ผ๋ก ๋น์ทํ๋ค. ์คํธ๋ฆผ์ map์ ์คํธ๋ฆผ์ ๊ฐ ์์์ ์ ๊ณต๋ ํจ์๋ฅผ ์ ์ฉํ๋ ์ฐ์ฐ์ด๋ค. ์ฌ๊ธฐ์ Optional ๊ฐ์ฒด๋ฅผ ์ต๋ ์์์ ๊ฐ์๊ฐ ํ ๊ฐ ์ดํ์ธ ๋ฐ์ดํฐ ์ปฌ๋ ์ ์ผ๋ก ์๊ฐํ ์ ์๋ค. Optional์ด ๊ฐ์ ํฌํจํ๋ฉด map์ ์ธ์๋ก ์ ๊ณต๋๋ ํจ์๊ฐ ๊ฐ์ ๋ฐ๊พผ๋ค.
1
2
3
public String getCarInsuranceName(Person person) {
return person.getCar().getInsurance().getName();
}
11.3.3 flatMap์ผ๋ก Optional ๊ฐ์ฒด ์ฐ๊ฒฐ
๋ค์์ฒ๋ผ map์ ์ด์ฉํด์ ์ฝ๋๋ฅผ ์ฌ๊ตฌํํ ์ ์๋ค.
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
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ด์ฐจ์ Optional์ ์ผ์ฐจ์ Optional๋ก ํ์คํํด์ผ ํ๋ค.
map์ ๋ฉ์๋์ฒ๋ผ ์คํธ๋ฆผ์ flatMap ๋ฉ์๋์ Optional์ flatMap ๋ฉ์๋์ ์ ์ฌ์ฑ์ ๋ณด์ฌ์ค๋ค.
์คํธ๋ฆผ
flatMap ๋ฉ์๋๋ก ์ ๋ฌ๋ ํจ์๋ ๊ฐ๊ฐ์ ์ ์ฌ๊ฐํ์ ๋ ๊ฐ์ ์ผ๊ฐํ์ ํฌํจํ๋ ์คํธ๋ฆผ์ผ๋ก ๋ณํํ๋ค. ์ฆ, map์ ์ ์ฉํ ๊ฒฐ๊ณผ๋ก ์ธ ๊ฐ์ ์คํธ๋ฆผ์ ํฌํจํ๋ ํ๋์ ์คํธ๋ฆผ์ด ์์ฑ๋๋ค. ํ์ง๋ง flatMap ๋ฉ์๋ ๋๋ถ์ ์ด์ฐจ์ ์คํธ๋ฆผ์ด ์ฌ์ฏ ๊ฐ์ ์ผ๊ฐํ์ ํฌํจํ๋ ์ผ์ฐจ์ ์คํธ๋ฆผ์ผ๋ก ๋ฐ๋๋ค.
Optional
Optional์ ์ ์ฅ๋ ์ ์ฌ๊ฐํ์ Optional์ ์ ์ฅ๋ ์ผ๊ฐํ์ผ๋ก ๋ฐ๊พผ๋ค. map ๋ฉ์๋์๋ค๋ฉด Optional ๋ด๋ถ์ ๋ค๋ฅธ Optional ๊ทธ๋ฆฌ๊ณ ๊ทธ ๋ด๋ถ์ ์ผ๊ฐํ์ด ์ ์ฅ๋์๊ฒ ์ง๋ง flatMap ๋ฉ์๋ ๋๋ถ์ ์ด์ฐจ์ Optional์ด ํ๋์ ์ผ๊ฐํ์ ํฌํจํ๋ ํ๋์ Optional๋ก ๋ฐ๋๋ค.
Optional๋ก ์๋์ฐจ์ ๋ณดํํ์ฌ ์ด๋ฆ ์ฐพ๊ธฐ
1
2
3
4
5
6
7
// Optional๋ก ์๋์ฐจ์ ๋ณดํํ์ฌ ์ด๋ฆ ์ฐพ๊ธฐ
public String getCarInsuranceName(Optional<Person> person) {
return person.flatMap(Person::getCar)
.flatMap(Car::getInsurance)
.map(Insurance::getName)
.orElse("Unknown"); //๊ฒฐ๊ณผ Optional์ด ๋น์ด์์ผ๋ฉด ๊ธฐ๋ณธ๊ฐ ์ฌ์ฉ
}
null์ ํ์ธํ๋๋ผ ์กฐ๊ฑด ๋ถ๊ธฐ๋ฌธ์ ์ถ๊ฐํด์ ์ฝ๋๋ฅผ ๋ณต์กํ๊ฒ ๋ง๋ค์ง ์์ผ๋ฉด์๋ ์ฝ๊ฒ ์ดํดํ ์ ์๋ ์ฝ๋๋ฅผ ์์ฑํ๋ค.
์ฐ์ getCarInsurance ๋ฉ์๋์ ์๊ทธ๋์ฒ๋ฅผ ๊ณ ์ณค๋ค. ์ฃผ์ด์ง ์กฐ๊ฑด์ ํด๋นํ๋ ์ฌ๋์ด ์์ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๋ํ Optional์ ์ฌ์ฉํ๋ฏ๋ก ๋๋ฉ์ธ ๋ชจ๋ธ๊ณผ ๊ด๋ จํ ์๋ฌต์ ์ธ ์ง์์ ์์กดํ์ง ์๊ณ ํ์ ์์คํ ์ ์ ์ํ ์ ์๋ค. ์ ํํ ์ ๋ณด ์ ๋ฌ์ ์ธ์ด์ ๊ฐ์ฅ ํฐ ๋ชฉํ ์ค ํ๋๋ค. Optional์ ์ธ์๋ก ๋ฐ๊ฑฐ๋ Optional์ ๋ฐํํ๋ ๋ฉ์๋๋ฅผ ์ ์ํ๋ค๋ฉด ๊ฒฐ๊ณผ์ ์ผ๋ก ์ด ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ๋ชจ๋ ์ฌ๋์๊ฒ ์ด ๋ฉ์๋๊ฐ ๋น ๊ฐ์ ๋ฐ๊ฑฐ๋ ๋น ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ์ ์์์ ์ ๋ฌธ์ํํด์ ์ ๊ณตํ๋ ๊ฒ๊ณผ ๊ฐ๋ค.
Optional์ ์ด์ฉํ Person/Car/Insurance ์ฐธ์กฐ ์ฒด์ธ
- Person, Car, Insurance์ ์ด๋ฆ ๋ฌธ์์ด ์ฐธ์กฐ(ํ์ดํ๋ผ์ธ ์ฐ์ฐ)
- 1๋จ๊ณ: Person์ Optional๋ก ๊ฐ์ผ ํ flatMap(Person::getCar) ํธ์ถ
- Optional ๋ด๋ถ์ Person์ Function(getCar ๋ฉ์๋)์ ์ ์ฉ
- getCar ๋ฉ์๋๋ Optional
๋ฅผ ๋ฐํํ๋ฏ๋ก Optional ๋ด๋ถ์ Person์ด Optional ๋ก ๋ณํ๋๋ฉด์ **์ค์ฒฉ Optional**์ด ์์ฑ - flatMap ์ฐ์ฐ์ผ๋ก Optional์ ํ์คํ
- 2๋จ๊ณ: Optional
๋ฅผ Optional ๋ก ๋ณํ - 3๋จ๊ณ: Insurance.getName()์ String์ผ๋ก ๋ฐํ
- flatMap์ ์ฌ์ฉํ ํ์๊ฐ ์๋ค.
- 4๋จ๊ณ: ๊ธฐ๋ณธ๊ฐ์ ์ ๊ณตํ๋ orElse ๋ฉ์๋ ์ฌ์ฉ
- ๋น์ด์์์ง๋ ๋ชจ๋ฅด๋ Optional
๊ฒฐ๊ณผ์ Optional์ด ๋น์์ ๋ ๊ธฐ๋ณธ๊ฐ์ ์ ๊ณตํ๋ orElse ๋ฉ์๋๋ฅผ ์ฌ์ฉ
- ๋น์ด์์์ง๋ ๋ชจ๋ฅด๋ Optional
11.3.4 Optional ์คํธ๋ฆผ ์กฐ์
์๋ฐ 9์์๋ Optional์ ํฌํจํ๋ ์คํธ๋ฆผ์ ์ฝ๊ฒ ์ฒ๋ฆฌํ ์ ์๋๋ก Optional์ stream() ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๋ค. Optional ์คํธ๋ฆผ์ ๊ฐ์ ๊ฐ์ง ์คํธ๋ฆผ์ผ๋ก ๋ณํํ ๋ ์ด ๊ธฐ๋ฅ์ ์ ์ฉํ๊ฒ ํ์ฉํ ์ ์๋ค.
์๋ ์ฝ๋๋ List
1
2
3
4
5
6
7
8
9
10
11
12
public Set<String> getCarInsuranceNames(List<Person> persons) {
return persons.stream()
// ์ฌ๋ ๋ชฉ๋ก์ ๊ฐ ์ฌ๋์ด ๋ณด์ ํ ์๋์ฐจ์ Optional<Car> ์คํธ๋ฆผ์ผ๋ก ๋ณํ
.map(Person::getCar)
// flatMap ์ฐ์ฐ์ ์ด์ฉํด Optional<Car>์ ํด๋น Optional<Insurance>๋ก ๋ณํ
.map(optCar -> optCar.flatMap(Car::getInsurance))
// Optional<Insurance>๋ฅผ ํด๋น ์ด๋ฆ์ Optional<String>์ผ๋ก ๋งคํ
.map(optIns -> optIns.map(Insurance::getName))
// Stream<Optional<String>>์ ํ์ฌ ์ด๋ฆ์ ํฌํจํ๋ Stream<String>์ผ๋ก ๋ณํ
.flatMap(Optional::stream)
// ๊ฒฐ๊ณผ ๋ฌธ์์ด์ ์ค๋ณต๋์ง ์์ ๊ฐ์ ๊ฐ๋๋ก ์งํฉ์ผ๋ก ์์ง
.collect(toSet());
์ ์ฝ๋์์ getCar ๋ฉ์๋๊ฐ ๋จ์ํ Car๊ฐ ์๋๋ผ Optional
- map ๋ณํ์ ์ํํ๊ณ Stream<Optoinal
>๋ฅผ ์ป๋๋ค. - ์ด์ด์ง๋ ๋ ๊ฐ์ map ์ฐ์ฐ์ ์ด์ฉํด Oprional
๋ฅผ Optional ๋ก ๋ณํํ ๋ค์ ์คํธ๋ฆผ์ด ์๋๋ผ ๊ฐ๊ฐ์ ์์์ ํ๋ ๊ฒ์ฒ๋ผ ๊ฐ๊ฐ์ Optional ์ผ๋ก ๋ณํํ๋ค.
์ ๋ณํ ๊ณผ์ ๊ฒฐ๊ณผ Stream<Optional
๋ค์์ฒ๋ผ filter, map์ ์์ฐจ์ ์ผ๋ก ์ด์ฉํด ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์๋ค.
1
2
3
4
Stream<Optional<String>> stream =
Set<String> result = stream.filter(Optional::isPresent)
.map(Optional::get)
.collect(toSet());
ํ์ง๋ง Optional ํด๋์ค์ stream() ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ฉด ํ ๋ฒ์ ์ฐ์ฐ์ผ๋ก ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์๋ค.
- Optional์ stream() ๋ฉ์๋๋ฅผ ํตํด Optional์ ์ ๊ฑฐํ๊ณ ๊ฐ์ ์ธ๋ฉํ๋ค.
์ด ๋ฉ์๋๋ flatMap ๋ฉ์๋๋ก ์ ๋ฌํ ์ ์๋ค.
11.3.5 ๋ํดํธ ์ก์ ๊ณผ Optional ์ธ๋ฉ
Optional ์ธ์คํด์ค์ ํฌํจ๋ ๊ฐ์ ์ฝ๋ ๋ค์ํ ๋ฐฉ๋ฒ
- get()
- ๊ฐ์ ์ฝ๋ ๊ฐ์ฅ ๊ฐ๋จํ ๋ฉ์๋์ด๋ฉด์ ๋์์ ๊ฐ์ฅ ์์ ํ์ง ์์ ๋ฉ์๋์ด๋ค.
- ๋ํ๋ ๊ฐ์ด ์์ผ๋ฉด ํด๋น ๊ฐ์ ๋ฐํ, ์์ผ๋ฉด NoSuchElementException ๋ฐ์
- Optional์ ๊ฐ์ด ๋ฐ๋์ ์๋ค๊ณ ๊ฐ์ ํ ์ ์๋ ์ํฉ์ด ์๋๋ฉด get ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ง ์๋ ๊ฒ์ด ๋ฐ๋์งํ๋ค. (๊ฒฐ๊ตญ ์ด ์ํฉ์ ์ค์ฒฉ๋ null ํ์ธ ์ฝ๋๋ฅผ ๋ฃ๋ ์ํฉ๊ณผ ํฌ๊ฒ ๋ค๋ฅด์ง ์๋ค.)
- orElse(T other)
- Optional์ด ๊ฐ์ ํฌํจํ์ง ์์ ๋ ๊ธฐ๋ณธ๊ฐ์ ์ ๊ณตํ ์ ์๋ค.
- orElseGet(Supplier<? extends T> other)
- orElse ๋ฉ์๋์ ๋์ํ๋ ๊ฒ์ผ๋ฅธ ๋ฒ์ ์ ๋ฉ์๋
- Optional์ ๊ฐ์ด ์์ ๋๋ง Supplier ์คํ
- ๋ํดํธ ๋ฉ์๋๋ฅผ ๋ง๋๋ ๋ฐ ์๊ฐ์ด ๊ฑธ๋ฆฌ๊ฑฐ๋(ํจ์จ์ฑ ๋๋ฌธ์) Optional์ด ๋น์ด์์ ๋๋ง ๊ธฐ๋ณธ๊ฐ์ ์์ฑํ๊ณ ์ถ๋ค๋ฉด orElseGet(Supplier<? extends T> other)๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
- orElseThrow(Supplier<? extends X> exceptionSupplier)
- Optional์ด ๋น์ด์์ ๋ ์์ธ๋ฅผ ๋ฐ์์ํจ๋ค๋ ์ ์์ get ๋ฉ์๋์ ๋น์ท
- ํ์ง๋ง ์ด ๋ฉ์๋๋ ๋ฐ์์ํฌ ์์ธ์ ์ข ๋ฅ ์ ํ ๊ฐ๋ฅ
- ifPresent(Consumer<? super T> consumer)
- ๊ฐ์ด ์กด์ฌํ ๋ ์ธ์๋ก ๋๊ฒจ์ค ๋์์ ์คํํ ์ ์๋ค.
- ๊ฐ์ด ์์ผ๋ฉด ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์๋๋ค.
์๋ฐ 9์์๋ ๋ค์์ ์ธ์คํด์ค ๋ฉ์๋๊ฐ ์ถ๊ฐ๋์๋ค.
- ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
- Optional์ด ๋น์์ ๋ ์คํํ ์ ์๋ Runnable์ ์ธ์๋ก ๋ฐ๋๋ค๋ ์ ๋ง ifPresent์ ๋ค๋ฆ
11.3.6 ๋ Optional ํฉ์น๊ธฐ
Person๊ณผ Car ์ ๋ณด๋ฅผ ์ด์ฉํด ๊ฐ์ฅ ์ ๋ ดํ ๋ณดํ๋ฃ๋ฅผ ์ ๊ณตํ๋ ๋ณดํํ์ฌ๋ฅผ ์ฐพ๋ ๋ช๋ช ๋ณต์กํ ๋น์ฆ๋์ค ๋ก์ง์ ๊ตฌํํ ์ธ๋ถ ์๋น์ค๊ฐ ์๋ค ๊ฐ์ ํ์.
1
2
3
4
5
public Insurance findCheapestInsurance(Person person, Car car) {
// ๋ค์ํ ๋ณดํํ์ฌ๊ฐ ์ ๊ณตํ๋ ์๋น์ค ์กฐํ
// ๋ชจ๋ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ ๋น๊ต
return cheapestCompany;
}
๋ Optional์ ์ธ์๋ก ๋ฐ์์ Optional
1
2
3
4
5
6
7
8
public Optional<Insurance> nullSafeFindCheapestInsurance(
Optional<Person> person, Optional<Car> car) {
if (person.isPresent() && car.isPresent()) {
return Optional.of(findCheapestInsurance(person.get(), car.get()));
} else {
return Optional.empty();
}
}
์ด ๋ฉ์๋์ ์ฅ์ ์ person๊ณผ car์ ์๊ทธ๋์ฒ๋ง์ผ๋ก ๋ ๋ค ์๋ฌด ๊ฐ๋ ๋ฐํํ์ง ์์ ์ ์๋ค๋ ์ ๋ณด๋ฅผ ๋ช ์์ ์ผ๋ก ๋ณด์ฌ์ฃผ๋ ๊ฒ์ด๋ค.
Quiz. Optional ์ธ๋ฉํ์ง ์๊ณ ๋ Optional ํฉ์น๊ธฐ
map๊ณผ flatMap ๋ฉ์๋๋ฅผ ์ด์ฉํด์ ๊ธฐ์กด์ nullSafeFindCheapestInsurance() ๋ฉ์๋๋ฅผ ํ ์ค์ ์ฝ๋๋ก ์ฌ๊ตฌํํ์์ค.
์ ๋ต
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์ ๋ฐํํ๋ค. ๋ฐ๋ฉด person๊ฐ์ด ์์ผ๋ฉด flatMap ๋ฉ์๋์ ํ์ํ Optional
๋ฅผ ๋ฐํํ๋ Function์ ์ ๋ ฅ์ผ๋ก person์ ์ฌ์ฉํ๋ค. ์ด ํจ์์ ๋ฐ๋์์๋ ๋ ๋ฒ์งธ Optional์ map์ ํธ์ถํ๋ฏ๋ก Optional์ด car๊ฐ์ ํฌํจํ์ง ์์ผ๋ฉด Function์ ๋น Optional์ ๋ฐํํ๋ฏ๋ก ๊ฒฐ๊ตญ nullSafeFindCheapestInsurance๋ ๋น Optional์ ๋ฐํํ๋ค. ๋ง์ง๋ง์ผ๋ก person๊ณผ car๊ฐ ๋ชจ๋ ์กด์ฌํ๋ฉด map ๋ฉ์๋๋ก ์ ๋ฌํ ๋๋ค ํํ์์ด findCheapestInsurance ๋ฉ์๋๋ฅผ ์์ ํ๊ฒ ํธ์ถํ ์ ์๋ค.
11.3.7 ํํฐ๋ก ํน์ ๊ฐ ๊ฑฐ๋ฅด๊ธฐ
ex) ๋ณดํํ์ฌ์ ์ด๋ฆ์ด โCambridgeInsuranceโ์ธ์ง ํ์ธ
1
2
3
4
Insurance insurance = ...;
if(insurance != null && "CambridgeInsurance".equals(insurance.getName())){
System.out.println("ok");
}
Optional ๊ฐ์ฒด์ filter ๋ฉ์๋๋ฅผ ์ด์ฉํด์ ๋ค์๊ณผ ๊ฐ์ด ์ฝ๋๋ฅผ ์ฌ๊ตฌํํ ์ ์๋ค.
1
2
3
4
Optional<Insurance> optInsurance = ...;
optInsurance.filter(insurance ->
"CambridgeInsurance".equals(insurance.getName())
.ifPresent(x -> System.out.println("ok"));
filter ๋ฉ์๋๋ ํ๋ ๋์ผ์ดํธ๋ฅผ ์ธ์๋ก ๋ฐ๋๋ค. Optional ๊ฐ์ฒด๊ฐ ๊ฐ์ ๊ฐ์ง๋ฉฐ ํ๋ ๋์ผ์ดํธ์ ์ผ์นํ๋ฉด filter ๋ฉ์๋๋ ๊ทธ ๊ฐ์ ๋ฐํํ๊ณ ๊ทธ๋ ์ง ์์ผ๋ฉด ๋น Optional ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค.
Optional์ด ๋น์ด์๋ค๋ฉด filter ์ฐ์ฐ์ ์๋ฌด ๋์๋ ํ์ง ์๋๋ค. Optional์ ๊ฐ์ด ์์ผ๋ฉด ๊ทธ ๊ฐ์ ํ๋ ๋์ผ์ดํธ๋ฅผ ์ ์ฉํ๋ค. ํ๋ ๋์ผ์ดํธ ๊ฒฐ๊ณผ๊ฐ true๋ฉด Optional์๋ ์๋ฌด ๋ณํ๋ ์ผ์ด๋์ง ์๋๋ค. ํ์ง๋ง ๊ฒฐ๊ณผ๊ฐ false๋ฉด ๊ฐ์ ์ฌ๋ผ์ง๊ณ Optional์ ๋น ์ํ๊ฐ ๋๋ค.
Quiz. Optional ํํฐ๋ง
์ฐ๋ฆฌ์ Person/Car/Insurance ๋ชจ๋ธ์ ๊ตฌํํ๋ Person ํด๋์ค์๋ ์ฌ๋์ ๋์ด ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ getAge ๋ฉ์๋๋ ์์๋ค. ๋ค์ ์๊ทธ๋์ฒ๋ฅผ ์ด์ฉํด getCarInsuranceName ๋ฉ์๋๋ฅผ ๊ณ ์น์์ค.
1
public String getCarInsuranceName(Optional<Person> person, int minAge)
์ฆ, ์ธ์ person์ด minAge ์ด์์ ๋์ด์ผ ๋๋ง ๋ณดํํ์ฌ ์ด๋ฆ์ ๋ฐํํ๋ค.
์ ๋ต
1 2 3 4 5 6 7
public String getCarInsuranceName(Optional<Person> person, int minAge) { return person.filter(p -> p.getAge() >= minAge) .flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse("Unknown"); //๊ฒฐ๊ณผ Optional์ด ๋น์ด์์ผ๋ฉด ๊ธฐ๋ณธ๊ฐ ์ฌ์ฉ }
11.4 Optional ์ ์ฌ์ฉํ ์ค์ฉ ์์
11.4.1 ์ ์ฌ์ ์ผ๋ก null์ด ๋ ์ ์๋ ๋์์ Optional๋ก ๊ฐ์ธ๊ธฐ
Map<String, Object> ํ์์ ๋งต์ด ์๋๋ฐ, ๋ค์์ฒ๋ผ key๋ก ๊ฐ์ ์ ๊ทผํ๋ค๊ณ ๊ฐ์ ํ์.
1
Object value = map.get("key");
๋ฌธ์์ด โkeyโ์ ํด๋นํ๋ ๊ฐ์ด ์์ผ๋ฉด null์ด ๋ฐํ๋ ๊ฒ์ด๋ค. map์์ ๋ฐํํ๋ ๊ฐ์ Optional๋ก ๊ฐ์ธ์ ์ด๋ฅผ ํด๊ฒฐํ ์ ์๋ค.
1
Optional<Object> value = Optional.ofNullable(map.get("key"));
์ ์ฝ๋๋ก null์ผ ์ ์๋ ๊ฐ์ Optional๋ก ์์ ํ๊ฒ ๋ณํํ ์ ์๋ค.
11.4.2 ์์ธ์ Optional ํด๋์ค
์๋ฐ API๋ ์ด๋ค ์ด์ ์์ ๊ฐ์ ์ ๊ณตํ ์ ์์ ๋ null์ ๋ฐํํ๋ ๋์ ์์ธ๋ฅผ ๋ฐ์์ํฌ ๋๋ ์๋ค. ์ ํ์ ์ธ ์๊ฐ ๋ฌธ์์ด์ ์ ์๋ก ๋ณํํ๋ ์ ์ ๋ฉ์๋ Integer.parseInt(String)์ด๋ค. ์ด ๋ฉ์๋๋ ๋ฌธ์์ด์ ์ ์๋ก ๋ฐ๊พธ์ง ๋ชปํ ๋ NumberFormatException์ ๋ฐ์์ํจ๋ค. ์ฆ, ๋ฌธ์์ด์ด ์ซ์๊ฐ ์๋๋ผ๋ ์ฌ์ค์ ์์ธ๋ก ์๋ฆฌ๋ ๊ฒ์ด๋ค.
๊ธฐ์กด์ ๊ฐ์ด null์ผ ์ ์์๋๋ if๋ฌธ์ผ๋ก null ์ฌ๋ถ๋ฅผ ํ์ธํ์ง๋ง ์์ธ๋ฅผ ๋ฐ์์ํค๋ ๋ฉ์๋์์๋ try/catch ๋ธ๋ก์ ์ฌ์ฉํด์ผ ํ๋ค๋ ์ ์ด ๋ค๋ฅด๋ค.
1
2
3
4
5
6
7
8
// ๋ฌธ์์ด์ ์ ์ Optional๋ก ๋ณํ
public static Optional<Integer> stringToInt(String s) {
try {
return Optional.of(Integer.parseInt(s));
} catch (NumberFormatException e) {
return Optional.empty();
}
}
์์ ๊ฐ์ ๋ฉ์๋๋ฅผ ํฌํจํ๋ ์ ํธ๋ฆฌํฐ ํด๋์ค OptionalUtility๋ฅผ ๋ง๋ค์ด๋ผ. ๊ทธ๋ฌ๋ฉด ํ์ํ ๋ OptionalUtility.stringToInt๋ฅผ ์ด์ฉํด ๋ฌธ์์ด Optional
11.4.3 ๊ธฐ๋ณธํ ํนํ Optional์ ์ฌ์ฉํ์ง ๋ง์์ผ ํ๋ ์ด์
์คํธ๋ฆผ์ฒ๋ผ Optional๋ ๊ธฐ๋ณธํ์ผ๋ก ํนํ๋ OptionalInt, OptionalLong, OptionalDouble ๋ฑ์ ํด๋์ค๋ฅผ ์ ๊ณตํ๋ค. ์ด์ ์ฝ๋์์ Optional
์คํธ๋ฆผ์ด ๋ง์ ์์๋ฅผ ๊ฐ์ง ๋๋ ๊ธฐ๋ณธํ ํนํ ์คํธ๋ฆผ์ ์ด์ฉํด์ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์์ง๋ง, Optional์ ์ต๋ ์์ ์๋ ํ ๊ฐ์ด๋ฏ๋ก Optional์์๋ ๊ธฐ๋ณธํ ํนํ ํด๋์ค๋ก ์ฑ๋ฅ์ ๊ฐ์ ํ ์ ์๋ค.
๊ธฐ๋ณธํ ํนํ Optional์ Optional ํด๋์ค์ ์ ์ฉํ ๋ฉ์๋ map, flatMap, filter ๋ฑ์ ์ง์ํ์ง ์์ผ๋ฏ๋ก ๊ธฐ๋ณธํ ํนํ Optional์ ์ฌ์ฉํ ๊ฒ์ ๊ถ์ฅํ์ง ์๋๋ค.
11.4.4 ์์ฉ
ex) ํ๋ก๊ทธ๋จ์ ์ค์ ์ธ์๋ก Properties๋ฅผ ์ ๋ฌ
1
2
3
4
Properties props = new Properties();
props.setProperty("a", "5");
props.setProperty("b", "true");
props.setProperty("c", "-3");
์ด์ ํ๋ก๊ทธ๋จ์์๋ Properties๋ฅผ ์ฝ์ด์ ๊ฐ์ ์ด ๋จ์์ ์ง์ ์๊ฐ์ผ๋ก ํด์ํ๋ค. ๋ค์๊ณผ ๊ฐ์ ๋ฉ์๋ ์๊ทธ๋์ฒ๋ก ์ง์ ์๊ฐ์ ์ฝ์ ๊ฒ์ด๋ค.
1
public int readDuration(Properties props, String name)
์ง์ ์๊ฐ์ ์์์ฌ์ผ ํ๋ฏ๋ก ๋ฌธ์์ด์ด ์์ ์ ์๋ฅผ ๊ฐ๋ฆฌํค๋ฉด ํด๋น ์ ์๋ฅผ ๋ฐํํ์ง๋ง ๊ทธ ์ธ์๋ 0์ ๋ฐํํ๋ค.
1
2
3
4
assertEquals(5, readDuration(param, "a"));
assertEquals(0, readDuration(param, "b"));
assertEquals(0, readDuration(param, "c"));
assertEquals(0, readDuration(param, "d"));
- ํ๋กํผํฐ a: ์์๋ก ๋ณํํ ์ ์๋ ๋ฌธ์์ด์ ํฌํจํ๋ฏ๋ก readDuration ๋ฉ์๋๋ 5๋ฅผ ๋ฐํ
- ํ๋กํผํฐ b: ์ซ์๋ก ๋ณํํ ์ ์๋ ๋ฌธ์์ด์ ํฌํจํ๋ฏ๋ก 0 ๋ฐํ
- ํ๋กํผํฐ c: ์์ ๋ฌธ์์ด์ ํฌํจํ๋ฏ๋ก 0 ๋ฐํ
- ํ๋กํผํฐ d: โdโ๋ผ๋ ์ด๋ฆ์ ํ๋กํผํฐ๋ ์์ผ๋ฏ๋ก 0 ๋ฐํ
1
2
3
4
5
6
7
8
9
10
11
12
13
//ํ๋กํผํฐ์์ ์ง์ ์๊ฐ์ ์ฝ๋ ๋ช
๋ นํ ์ฝ๋
public int readDuration(Properties props, String name) {
String value = props.getProperty(name);
if (value != null) { //์์ฒญํ ์ด๋ฆ์ ํด๋นํ๋ ํ๋กํผํฐ๊ฐ ์กด์ฌํ๋์ง ํ์ธ
try {
int i = Integer.parseInt(value); //๋ฌธ์์ด ํ๋กํผํฐ๋ฅผ ์ซ์๋ก ๋ณํํ๊ธฐ ์ํด ์๋
if (i > 0) { //๊ฒฐ๊ณผ ์ซ์๊ฐ ์์์ธ์ง ํ์ธ
return i;
}
} catch (NumberFormatException nfe) { }
}
return 0; // ํ๋์ ์กฐ๊ฑด์ด๋ผ๋ ์คํจํ๋ฉด 0 ๋ฐํ
}
if๋ฌธ๊ณผ try/catch ๋ธ๋ก์ด ์ค์ฒฉ๋๋ฉด์ ๊ตฌํ ์ฝ๋๊ฐ ๋ณต์กํด์ก๊ณ ๊ฐ๋ ์ฑ๋ ๋๋น ์ก๋ค.
Quiz. Optional๋ก ํ๋กํผํฐ์์ ์ง์ ์๊ฐ ์ฝ๊ธฐ
์ ๋ช ๋ นํ ์ฝ๋๋ฅผ ํ๋์ ์ ์ฐํ ์ฝ๋๋ก ์ฌ๊ตฌํํ๋ผ.
1 2 3 4 5 6
public int readDuration(Properties props, String name) { return Optional.ofNullable(props.getProperty(name)) .flatMap(OptionalUtility::stringToInt) .filter(i -> i > 0) .orElse(0); }
- ofNullable : ์์ฒญํ ํ๋กํผํฐ๊ฐ ์กด์ฌํ์ง ์์ ๋
- flatMap : OptionalUtility.stringToInt ๋ฉ์๋ ์ฐธ์กฐ๋ฅผ ์ ๋ฌํด Optional
์ Optional ๋ก ๋ฐ๊ฟ ์ ์๋ค. - filter: ์์ ํํฐ๋ง
์ด๋ค ์ค ํ๋๋ผ๋ ๋น Optional์ ๋ฐํํ๋ฉด orElse ๋ฉ์๋์ ์ํด ๊ธฐ๋ณธ๊ฐ 0์ด ๋ฐํ๋๋ค. ๊ทธ๋ ์ง ์๋ค๋ฉด Optional์ ๋ค์ด์๋ ์์๋ฅผ ๋ฐํํ๋ค.
Optional๊ณผ ์คํธ๋ฆผ์์ ์ฌ์ฉํ ๋ฐฉ์์ ์ฌ๋ฌ ์ฐ์ฐ์ด ์๋ก ์ฐ๊ฒฐ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ง์๋ฌธ๊ณผ ๋น์ทํ ํ์์ ๊ฐ๋๋ค.