item 55 SeungminLee - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki
์ต์ ๋ ๋ฐํ์ ์ ์คํ ํ๋ผ
๊ฐ์ ๋ฐํํ์ง ๋ชปํ ๊ฐ๋ฅ์ฑ์ด ์๊ณ , ํธ์ถํ ๋๋ง๋ค ๋ฐํ๊ฐ์ด ์์ ๊ฐ๋ฅ์ฑ์ ์ผ๋์ ๋ฌ์ผ ํ๋ ๋ฉ์๋๋ผ๋ฉด ์ต์ ๋์ ๋ฐํํด์ผ ํ ์ํฉ์ผ ์ ์๋ค. ํ์ง๋ง ์ต์ ๋ ๋ฐํ์๋ ์ฑ๋ฅ ์ ํ๊ฐ ๋ค๋ฐ๋ฅด๋, ์ฑ๋ฅ์ ๋ฏผ๊ฐํ ๋ฉ์๋๋ผ๋ฉด null์ ๋ฐํํ๊ฑฐ๋ ์์ธ๋ฅผ ๋์ง๋ ํธ์ด ๋์ ์ ์๋ค. ๋ํ ์ต์ ๋์ ๋ฐํ๊ฐ ์ด์ธ์ ์ฉ๋๋ก ์ฐ๋ ๊ฒฝ์ฐ๋ ๋งค์ฐ ๋๋ฌผ๋ค.
- ์์ธ๋ฅผ ๋์ง๋ค
- ์์ธ๋ ์ง์ง ์์ธ์ ์ธ ์ํฉ์์๋ง ์ฌ์ฉํด์ผ ํ๋ค.
- ์์ธ๋ฅผ ์์ฑํ ๋ ์คํ ์ถ์ ์ ์ฒด๋ฅผ ์บก์ณํ๋ฏ๋ก ๋น์ฉ๋ ๋ง๋ง์น ์๋ค.
- null ์ ๋ฐํํ๋ค
- null์ ๋ฐํํ ์ ์๋ ๋ฉ์๋๋ฅผ ํธ์ถํ ๋๋ ๋ณ๋์ null ์ฒ๋ฆฌ ์ฝ๋๋ฅผ ์ถ๊ฐํด๋ ํ๋ค.
- null์ฒ๋ฆฌ๋ฅผ ๋ฌด์ํ๋ค๋ฉด ์ค์ ์์ธ๊ณผ๋ ์ ํ ์๊ด ์๋ ์ฝ๋์์ NullPointerException์ด ๋ฐ์ํ ์ ์๋ค.
Optional๋ null์ด ์๋ Tํ์ ์ฐธ์กฐ๋ฅผ ํ๋ ๋ด๊ฑฐ๋ ํน์ ์๋ฌด๊ฒ๋ ๋ด์ง ์์ ์ ์๋ค. ์๋ฌด๊ฒ๋ ๋ด์ง ์์ ์ต์ ๋์ ๋น์๋ค๊ณ ๋งํ๋ค. ๋ฐ๋๋ก ์ด๋ค ๊ฐ์ ๋ด์ ์ต์ ๋์ ๋น์ด์์ง ์๋ค๊ณ ํ๋ค. ์ต์ ๋์ ์์๋ฅผ ์ต๋ 1๊ฐ ๊ฐ์ง ์ ์๋ ๋ถ๋ณ ์ปฌ๋ ์ ์ด๋ค.
- ๋ถ๋ณ ์ปฌ๋ ์ ์ด๋ผ๊ณ ํด์ Optional๊ฐ Collection๋ฅผ ๊ตฌํํ ๊ฒ์ ์๋๋ค. Optional๋ Object๋ฅผ ์์๋ฐ์๋ค.
- ๋ณดํต์ T๋ฅผ ๋ฐํํด์ผ ํ์ง๋ง ํน์ ์กฐ๊ฑด์์๋ ์๋ฌด๊ฒ๋ ๋ฐํํ์ง ์์์ผ ํ ๋ T ๋์ Optional๋ฅผ ๋ฐํํ๋ฉด ๋๋ค.
- Optional์ ๋ฐํํ๋ ๋ฉ์๋๋ ์์ธ๋ฅผ ๋์ง๋ ๋ฉ์๋๋ณด๋ค ์ ์ฐํ๊ณ ์ฌ์ฉํ๊ธฐ ์ฌ์ฐ๋ฉฐ, null์ ๋ฐํธ๋ํ๋ ๋ฉ์๋๋ณด๋ค ์ค๋ฅ ๊ฐ๋ฅ์ฑ์ด ์ ๋ค.
/*
Optional ์ ์ฌ์ฉํ์ง ์๊ณ ์์ธ๋ฅผ ๋์ ธ์ค๋ค
*/
public static <E extends Comparable<E>> E max(Collection<E> c) {
if (c.isEmpty())
throw new IllegalArgumentException("๋น ์ปฌ๋ ์
");
E result = null;
for (E e: c) {
if(result == null || e.compareTo(result) > 0)
result = Objects.requireNonNull(e);
}
return result;
}
/*
Optional ์ ์ฌ์ฉ
*/
public static <E extends Comparable<E>> Optional<E> maxOptional(Collection<E> c) {
if (c.isEmpty())
return Optional.empty();
E result = null;
for (E e: c) {
if(result == null || e.compareTo(result) > 0)
result = Objects.requireNonNull(e);
}
return Optional.of(result);
}
/*
Optional + stream ์ฌ์ฉ
* Stream์ ์ข
๋จ ์ฐ์ฐ ์ค ์๋น์๊ฐ Optional์ ๋ฐํํ๋ค
*/
public static <E extends Comparable<E>> Optional<E> maxStream(Collection<E> c) {
return c.stream().max(Comparator.naturalOrder());
}
- Optional์ ์ฌ์ฉํ ๋๋ ์ ์ ํ ์ ์ ์ฑ ํฐ๋ฆฌ๋ฅผ ์ฌ์ฉํด ์ต์ ๋์ ์์ฑํด์ฃผ๋ฉด ๋๋ค.
- Optional.empty() ๋ ๋น ์ต์ ๋์ ๋ฐํํ๋ค.
- Optional.of(value) ์ Null์ ๋ฃ์ผ๋ฉด NullPointerException ์ด ๋ฐ์ํ๋ ์ฃผ์ํ์
- Optional.ofNullable(value)๋ฅผ ํ๋ฉด Null์ ๋ฐํํ ์ ์๊ธฐ๋ํ์ง๋ง ์ต์ ๋์ ๋์ ํ ์ทจ์ง๋ฅผ ์์ ํ ๋ฌด์ํ๊ธฐ ๋๋ฌธ์ ์ต์ ๋์ ๋ฐํํ๋ ๋ฉ์๋์์๋ ์ ๋ Null์ ๋ฐํํ์ง ๋ง์
Optional์ ๊ฒ์ฌ ์์ธ์ ์ทจ์ง๊ฐ ๋น์ทํ๋ค. ์ฆ, ๋ฐํ๊ฐ์ด ์์ ์๋ ์์์ API ์ฌ์ฉ์์๊ฒ ๋ช ํํ ์๋ ค์ค๋ค. ๋น๊ฒ์ฌ ์์ธ๋ฅผ ๋์ง๊ฑฐ๋ null์ ๋ฐํํ๋ค๋ฉด API ์ฌ์ฉ์๊ฐ ๊ทธ ์ฌ์ค์ ์ธ์งํ์ง ๋ชปํ๋ค. ํ์ง๋ง ๊ฒ์ฌ ์์ธ๋ฅผ ๋์ง๋ฉด ํด๋ผ์ด์ธํธ์์๋ ๋ฐ๋์ ์ด์ ๋์ฒํ๋ ์ฝ๋๋ฅผ ์์ฑํด ๋ฃ์ด์ผ ํ๋ค. ๋น์ทํ๊ฒ, ๋ฉ์๋๊ฐ Optional์ ๋ฐํํ๋ค๋ฉด ํด๋ผ์ด์ธํธ๋ ๊ฐ์ ๋ฐ์ง ๋ชปํ์ ๋ ์ทจํ ํ๋์ ์ ํํด์ผ ํ๋ค.
int result = maxOptional(empty).orElse(-1);
// Supplier ๊ณผ orElseGet ์ฌ์ฉ
Supplier<Integer> defaultSupplier = () -> -1;
int unWrap = resultNumber1.orElseGet(defaultSupplier)
// ๊ฐ์ด ์์๊ฑฐ๋ผ ํ์ ํ๊ณ get
int result4 = maxOptional(number1).get();
// orElseThrow
int result2 = maxOptional(number1).orElseThrow(IllegalArgumentException::new);
int result3 = maxOptional(empty).orElseThrow(NullPointerException::new);
- orElse() ๋ก ๊ธฐ๋ณธ๊ฐ ์ค์ ํด์ฃผ๊ธฐ
- orElseThrow ๋ก ์ํ๋ ์์ธ ๋์ง๊ธฐ (maxOptional ์ ๊ฑธ์ด๋ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด orElseThrow์ ์๋ ์์ธ๋ฅผ ๋ฐ์์ํจ๋ค)
- ํญ์ ๊ฐ์ด ์ฑ์์ ธ ์๋ค๊ณ ํ์ ํ๊ณ get ์ฌ์ฉ
- ๊ธฐ๋ณธ๊ฐ ์ค์ ํ๋ ๋น์ฉ์ด ๋ถ๋ต์ค๋ฝ๋ค๋ฉด Supplier๋ฅผ ์ธ์๋ก ๋ฐ๋ orElseGet์ ์ฌ์ฉํ์. ๊ฐ์ด ์ฒ์์ผ๋ก ํ์ํ๊ฒ ๋ ๋ Supplier๋ก ์์ฑํด์ ์ด๊ธฐ ์ค์ ๋น์ฉ์ ๋ฎ์ถ ์ ์๋ค.
- ์์ ์ ๊ณต๋ ๊ธฐ๋ณธ ๋ฉ์๋ ์ธ์ filter, map, flatMap, ifPresent ๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
- ifPresent๋ ๋ง์ ์๋น์ ์ํผ ์ธ๊ธํ ๋ฉ์๋๋ค๋ก ๋์ฒดํ ์ ์๋ค. (์ฌ์ฉ ๋น์ถ)
//ifPresent ์์
Optional<ProcessHandler> parentProcess = ph.parent();
System.out.println("PID:" + (parentProcess.isPresent() ? String.valueOf(parentProcess.get().pid()) : "N/A"));
//Optional map ์ฌ์ฉ
System.out.println("PID:" + ph.parent().map(h->String.valueOf(h.pid())).orElse("N/A"));
// stream ์ฌ์ฉ
// isPresent๊ฐ ์ฌ์ค์ผ ๊ฒฝ์ฐ ๊ฐ์ ๊บผ๋ด์ Optional::get์ ๋งตํ
streamOfOptionals.filter(Optional::isPresent).map(Optional::get)
//optional stream ์ฌ์ฉ
//optional์ ๊ฐ์ด ์๊ฑฐ๋ ์๊ฑฐ๋ ๋ค stream์ผ๋ก ๋ณํ์ ํด์ค
streamOfOptionals.flatMap(Optional::stream)
์ปฌ๋ ์ , ์คํธ๋ฆผ, ๋ฐฐ์ด, ์ต์ ๋ ๊ฐ์ ์ปจํ ์ด๋ ํ์ ์ ์ต์ ๋๋ก ๊ฐ์ธ๋ฉด ์๋๋ค. ๋น Optional<List>๋ฅผ ๋ฐํํ๊ธฐ ๋ณด๋ค๋ ๋น List๋ฅผ ๋ฐํํ๋๊ฒ ์ข๋ค. ๋น ์ปจํ ์ด๋๋ฅผ ๊ทธ๋๋ก ๋ฐํํ๋ฉด ํด๋ผ์ด์ธํธ์ ์ต์ ๋ ์ฒ๋ฆฌ ์ฝ๋๋ฅผ ๋ฃ์ง ์์๋ ๋๋ค.
๊ฒฐ๊ณผ๊ฐ ์์ ์ ์์ผ๋ฉฐ, ํด๋ผ์ด์ธํธ๊ฐ ์ด ์ํฉ์ ํน๋ณํ๊ฒ ์ฒ๋ฆฌํด์ผ ํ๋ค๋ฉด Optional๋ฅผ ๋ฐํํ๋ค.
- Optional๋ ์์ฐํ๊ฒ ์๋ก ํ ๋นํ๊ณ ์ด๊ธฐํํด์ผ ํ๋ ๊ฐ์ฒด์ด๊ณ , ๊ทธ ์์์ ๊ฐ์ ๊บผ๋ด๋ ค๋ฉด ๋ฉ์๋๋ฅผ ํธ์ถํด์ผ ํ๋ ํ ๋จ๊ณ๋ฅผ ๋ ๊ฑฐ์น๋ค. ๊ทธ๋์ ์ฑ๋ฅ์ด ์ค์ํ ์ํฉ์์๋ ์ต์ ๋์ด ๋ง์ง ์์ ์ ์๋ค.
- ๋ฐ์ฑ๋ ๊ธฐ๋ณธํ์ ์ ๋ด๋ ์ต์ ๋์ ๊ธฐ๋ณธ ํ์ ์์ฒด๋ณด๋ค ๋ฌด๊ฒ๋ค. ๊ทธ๋์ OptionalInt, OptionalLong, OptionalDouble ์ ์ฌ์ฉํ๋ค. ๋ฐ์ฑ๋ ๊ธฐ๋ณธ ํ์ ์ ๋ด์ ์ต์ ๋์ ๋ฐํํ๋ ์ผ์ ์๋๋ก ํ์.
๊ฐ์ผ๋ก ์ฌ์ฉํ๋ค๋ฉด ๋งต ์์ ํค๊ฐ ์๋ค๋ ์ฌ์ค์ ๋ํ๋ด๋ ๋ฐฉ๋ฒ์ด ๋๊ฐ์ง๊ฐ ๋๋ค. ํ๋๋ ํค ์์ฒด๊ฐ ์๋ ๊ฒฝ์ฐ๊ณ ๋ค๋ฅธ ํ๋๋ ํค๋ ์์ง๋ง ๊ทธ ํค๊ฐ ์์ด ๋น ์ต์ ๋์ผ ๊ฒฝ์ฐ๋ค. ๋ ๋ณต์ก์ฑ๋ง ๋์ฌ ํผ๋๊ณผ ์ค๋ฅ ๊ฐ๋ฅ์ฑ์ ํค์ด๋ค.
์ต์ ๋์ ์ปฌ๋ ์ ์ ํค, ๊ฐ, ์์๋ ๋ฐฐ์ด์ ์์๋ก ์ฌ์ฉํ๋๊ฒ ์ ์ ํ ์ํฉ์ ๊ฑฐ์ ์๋ค!
ํด๋์ค๋ฅผ ๋ง๋ค๋ ์ธ์คํด์ค์ ํ๋ ์ค ์๋น์๊ฐ ํ์๊ฐ ์๋๊ณ , ๊ทธ ํ๋๋ค์ด ๊ธฐ๋ณธํ์ ์ด๋ผ ๊ฐ์ด ์์์ ๋ํ๋ผ ๋ฐฉ๋ฒ์ด ๋ง๋ ์น ์๋ค๋ฉด ํ๋์ Getter ๋ฉ์๋๋ค์ด ์ต์ ๋์ ๋ฐํํ๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด๋ค.