Post

๐Ÿน 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**๋ผ๋Š” ์ƒˆ๋กœ์šด ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค. 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์ด๋ฏ€๋กœ map ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ getCar๋Š” Optional ํ˜•์‹์˜ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ฆ‰, map ์—ฐ์‚ฐ์˜ ๊ฒฐ๊ณผ๋Š” Optional<Oprional> ํ˜•์‹์˜ ๊ฐ์ฒด๋‹ค. getInsurance๋Š” ๋˜ ๋‹ค๋ฅธ Optional ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ getInsurance ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์•„๋ž˜ ๊ทธ๋ฆผ๊ฐ™์€ ์ค‘์ฒฉ 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 ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉ

11.3.4 Optional ์ŠคํŠธ๋ฆผ ์กฐ์ž‘

์ž๋ฐ” 9์—์„œ๋Š” Optional์„ ํฌํ•จํ•˜๋Š” ์ŠคํŠธ๋ฆผ์„ ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก Optional์— stream() ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค. Optional ์ŠคํŠธ๋ฆผ์„ ๊ฐ’์„ ๊ฐ€์ง„ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ ์ด ๊ธฐ๋Šฅ์„ ์œ ์šฉํ•˜๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ๋Š” List์„ ์ธ์ˆ˜๋กœ ๋ฐ›์•„ ์ž๋™์ฐจ๋ฅผ ์†Œ์œ ํ•œ ์‚ฌ๋žŒ๋“ค์ด ๊ฐ€์ž…ํ•œ ๋ณดํ—˜ ํšŒ์‚ฌ์˜ ์ด๋ฆ„์„ ํฌํ•จํ•˜๋Š” Set์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

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๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ์‚ฌ๋žŒ์ด ์ž๋™์ฐจ๋ฅผ ๊ฐ€์ง€์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ๋Š” ์ƒํ™ฉ์ด๋‹ค.

  1. map ๋ณ€ํ™˜์„ ์ˆ˜ํ–‰ํ•˜๊ณ  Stream<Optoinal>๋ฅผ ์–ป๋Š”๋‹ค.
  2. ์ด์–ด์ง€๋Š” ๋‘ ๊ฐœ์˜ map ์—ฐ์‚ฐ์„ ์ด์šฉํ•ด Oprional๋ฅผ Optional๋กœ ๋ณ€ํ™˜ํ•œ ๋‹ค์Œ ์ŠคํŠธ๋ฆผ์ด ์•„๋‹ˆ๋ผ ๊ฐ๊ฐ์˜ ์š”์†Œ์— ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ๊ฐ๊ฐ์„ Optional์œผ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.

์œ„ ๋ณ€ํ™˜ ๊ณผ์ • ๊ฒฐ๊ณผ Stream<Optional>์„ ์–ป๋Š”๋ฐ ์‚ฌ๋žŒ์ด ์ฐจ๋ฅผ ๊ฐ–๊ณ  ์žˆ์ง€ ์•Š๊ฑฐ๋‚˜ ๋˜๋Š” ์ฐจ๊ฐ€ ๋ณดํ—˜์— ๊ฐ€์ž…๋˜์–ด ์žˆ์ง€ ์•Š์•„ ๊ฒฐ๊ณผ๊ฐ€ ๋น„์–ด์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ๋งˆ์ง€๋ง‰ ๊ฒฐ๊ณผ๋ฅผ ์–ป์œผ๋ ค๋ฉด ๋นˆ 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() ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜๋ฉด ํ•œ ๋ฒˆ์˜ ์—ฐ์‚ฐ์œผ๋กœ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

  1. 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๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” null ์•ˆ์ „ ๋ฒ„์ „์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผํ•œ๋‹ค ๊ฐ€์ •ํ•œ๋‹ค. ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•œ ๊ฐ’ ์ค‘ ํ•˜๋‚˜๋ผ๋„ ๋น„์–ด์žˆ์œผ๋ฉด ๋นˆ Optional๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. Optional ํด๋ž˜์Šค๋Š” Optional์ด ๊ฐ’์„ ํฌํ•จํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ifPresent๋ผ๋Š” ๋ฉ”์„œ๋“œ๋„ ์ œ๊ณตํ•œ๋‹ค.

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 ๋Œ€์‹  OptionalInt๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ŠคํŠธ๋ฆผ์ด ๋งŽ์€ ์š”์†Œ๋ฅผ ๊ฐ€์งˆ ๋•Œ๋Š” ๊ธฐ๋ณธํ˜• ํŠนํ™” ์ŠคํŠธ๋ฆผ์„ ์ด์šฉํ•ด์„œ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์—ˆ์ง€๋งŒ, 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๊ณผ ์ŠคํŠธ๋ฆผ์—์„œ ์‚ฌ์šฉํ•œ ๋ฐฉ์‹์€ ์—ฌ๋Ÿฌ ์—ฐ์‚ฐ์ด ์„œ๋กœ ์—ฐ๊ฒฐ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์งˆ์˜๋ฌธ๊ณผ ๋น„์Šทํ•œ ํ˜•์‹์„ ๊ฐ–๋Š”๋‹ค.

This post is licensed under CC BY 4.0 by the author.