DevLog ๐ถ
[๋ชจ๋์๋ฐ์ธ์ก์ ] ๋๋ค ํํ์ : ์ต๋ช ํจ์๋ฅผ ๊ฐ๊ฒฐํ๊ฒ ๋ง๋ค๊ธฐ ๋ณธ๋ฌธ
[๋ชจ๋์๋ฐ์ธ์ก์ ] ๋๋ค ํํ์ : ์ต๋ช ํจ์๋ฅผ ๊ฐ๊ฒฐํ๊ฒ ๋ง๋ค๊ธฐ
dolmeng2 2023. 2. 27. 18:53๐ฌ ๋ชจ๋ ์๋ฐ ์ธ ์ก์ ์ฑํฐ 3์ ์ฝ๊ณ ์ ๋ฆฌํ ๊ธ์ ๋๋ค.
โ๏ธ ๋๋ค๊ฐ ๋ญ๋ฐ์?
์ง๋ ์ฑํฐ์์๋ ๋์ ํ๋ผ๋ฏธํฐํ๋ฅผ ํตํด์ ํ๋ผ๋ฏธํฐ๋ก ๋ฉ์๋์ ๋์ ์์ฒด๋ฅผ ์ ๋ฌํด์ฃผ๋ ๊ฒ์ ๋ฐฐ์ ๋ค. ์ด๋, ๋ฉ์๋์ ๋์์ ์ ๋ฌํ๊ธฐ ์ํด์ ๋ณ๋์ @Override ์ด๋ ธํ ์ด์ ์ด๋ ์์๋ ๋ฉ์๋ ์ด๋ฆ ๋ฑ, ๋์ ์ธ์ ๋ค๋ฅธ ์ฝ๋๋ค์ด ๋ฐ๋ณต๋์ด ์๋นํ ๋ถํธํ๋ค. ๋๋ค ํํ์์ ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์, ๋จ์ํ '๋์์ ๋ํ ์ฝ๋๋ง' ๋ฉ์๋๋ก ์ ๋ฌํ ์ ์๋๋ก ์ต๋ช ํจ์๋ฅผ ๋จ์ํํ ๊ฒ์ด๋ค.
๋๋ค ํํ์์ ๋ค์๊ณผ ๊ฐ์ ํน์ง์ ๊ฐ์ง๋ค.
๐ฌ ๋ฉ์๋์ ์ด๋ฆ์ด ์์ผ๋๊น “์ต๋ช ”์ด๋ค. (๋ฉ์๋์ ๋ํ ๋ค์ด๋ฐ์ ๊ณ ๋ฏผํ ํ์๊ฐ ์๋ค!)
- ์ด๋ฆ์ ์์ง๋ง, ํ๋ผ๋ฏธํฐ ๋ฆฌ์คํธ์ ๋ฐ๋, ๋ฐํ ํ์, ๋ฐ์ ๊ฐ๋ฅํ ์์ธ ๋ฆฌ์คํธ๋ ๊ฐ์ง ์ ์๋ค.
๐ฌ ํจ์ : ํน์ ํด๋์ค์ ์ข ์๋์ง ์๊ณ , ๋ ๋ฆฝ์ ์ผ๋ก ๊ตฌ์ฑ๋๋ค. ํ์ง๋ง ๋ฉ์๋์ฒ๋ผ ํ๋ผ๋ฏธํฐ, ๋ฐ๋, ๋ฆฌํด๊ฐ, ๊ฐ๋ฅํ ์์ธ๊น์ง ๋ชจ๋ ํฌํจํ๋ค!
- ์ฑํฐ 1์์ ์ค๋ช ํ๋ (๋ฉ์๋ vs ํจ์์ ๋ด์ฉ์ ์๊ฐํ์!)
๐ฌ ์ ๋ฌ : ๋๋ค ํํ์์ ๋ง์น ‘์ผ๊ธ ๊ฐ์ฒด’์ฒ๋ผ ์ธ์๋ก ์ ๋ฌํ๊ฑฐ๋, ๋ณ์๋ก ์ ์ฅ์ด ๊ฐ๋ฅํ๋ค.
๐ฌ ๊ฐ๊ฒฐ์ฑ : ์ฝ๋๊ฐ ๊ฐ๊ฒฐํด์ง๋ค! ๋จ์ํ ๋์ ์์ฒด๋ง ๋๊ฒจ์ค ์ ์๋ค.
๋๋ค ํํ์์ ์ด๋ป๊ฒ ๊ตฌ์ฑ๋์ด ์์๊น?
(Crew a1, Crew a2) -> Integer.compare(a1.getAge(), a2.getAge());
(Crew a1, Crew a2) : ๋๋ค ํ๋ผ๋ฏธํฐ, ํ์ฌ ์ฝ๋์์๋ compareTo์ ์ฌ์ฉ๋๋ ํ๋ผ๋ฏธํฐ 2๊ฐ๋ฅผ ์๋ฏธํ๋ค.
→ : ํ์ดํ, ํ๋ผ๋ฏธํฐ ๋ฆฌ์คํธ์ ๋ฐ๋๋ฅผ ๊ตฌ๋ถํด์ฃผ๋ ์ญํ ์ ํ๋ค.
Integer.compare(a1.getAge(), a2.getAge()) : ๋๋ค ๋ฐ๋, ๋๋ค์ ๋ฐํ๊ฐ์ ํํํด์ค๋ค.
๋ํ, ๋๋ค๋ ํฌ๊ฒ ํํ์ ์คํ์ผ๊ณผ ๋ธ๋ก ์คํ์ผ๋ก ํํํ ์ ์๋ค.
ํํ์ ์คํ์ผ: () -> "Hello Crew!”
๋ธ๋ก ์คํ์ผ: () → { return “Hello Crew!”; }
๋ธ๋ก์์๋ return๊ณผ ์ธ๋ฏธ์ฝ๋ก ์ ๋ถ์ฌ์ค์ผ ํ๋ค. ์ฃผ๋ก ์ฌ๋ฌ ํ์ ์ ๋ ฅํด์ผ ํ ๋ ์ฌ์ฉํ๋ฉฐ, ๊ฐ๊ฒฐํ ๊ฒฝ์ฐ ํํ์ ์คํ์ผ๋ก๋ ๋ง๋ค ์ ์๋ค.
โ๏ธ ๊ทธ๋์ ๋๋ค… ์ด๋์ ์ฌ์ฉํ๋๋ฐ?
๋๋ค๋ก ๊ฐ๊ฒฐํด์ง๋ค๋ ๊ฒ๊น์ง๋ ์๊ฒ ๋์๋ค. ํ์ง๋ง, ์ด๋ฅผ ์ด๋ป๊ฒ ์์ฉํ๋ฉด ์ข์์ง ์์ง ๊ฐ์ด ์กํ์ง ์๋๋ค. ๊ต์ฌ์์๋ ๋ค์๊ณผ ๊ฐ์ด ๋๋ค์ ์ฌ์ฉ๋ฒ์ ์ค๋ช ํ๋ค.
๐ก ์ฃผ๋ก ํจ์ํ ์ธํฐํ์ด์ค์์ ๋๋ค๋ฅผ ์ฌ์ฉํฉ๋๋ค.
๊ฐ์๊ธฐ ํจ์ํ ์ธํฐํ์ด์ค? ๋ฌด์จ ๋ง์ธ์ง ์ดํดํ๊ธฐ ์ด๋ ค์ธ ์ ์์ง๋ง, ์ฐ๋ฆฌ๋ ์ด๋ฏธ ํจ์ํ ์ธํฐํ์ด์ค๋ฅผ ๋ณธ ์ ์ด ์๋ค. ํจ์ํ ์ธํฐํ์ด์ค๋ '๋ํดํธ ๋ฉ์๋์ ์ ๋ฌด์ ๊ด๊ณ์์ด, ์ค์ง ์ถ์ ๋ฉ์๋๋ฅผ 1๊ฐ๋ง ๊ฐ์ง๋ ์ธํฐํ์ด์ค'์ด๋ค. ์๋๋ ์๋ฐ์์ ์ ๊ณตํ๋ ๋ํ์ ์ธ ํจ์ํ ์ธํฐํ์ด์ค ์ค ํ๋์ธ Predicate์ด๋ค.
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
์ฐ๋ฆฌ๋ ์ฑํฐ 2์์ ์ฌ์ฉํ์๋ ๋ค์ค ์กฐ๊ฑด์ ๋ํด ๊ฒ์ฆ์ ์ํด Predicate ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ์๋ค. ์ฌ๊ธฐ์ Predicate<T>๋ฅผ ํจ์ํ ์ธํฐํ์ด์ค๋ผ๊ณ ํ ์ ์์ผ๋ฉฐ, ์ค์ง ํ๋์ ์ถ์ ๋ฉ์๋์ธ 'test()'๋ง ๊ฐ์ง๊ณ ์๋ค.
์ฐ๋ฆฌ๊ฐ ํํ ์ ๋ ฌํ ๋ ์ฌ์ฉํ๋ Comparator<T> ์ญ์, ํจ์ํ ์ธํฐํ์ด์ค์ ์ผ์ข ์ด๋ค.
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
compare()๋ผ๋ ์ถ์ ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ์๋ฐ์์๋ ๋ช ์์ ์ผ๋ก ํด๋น ์ธํฐํ์ด์ค๊ฐ ํจ์ํ ์ธํฐํ์ด์ค์์ ์๋ฆฌ๊ธฐ ์ํด์ @FunctionalInterface๋ผ๋ ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ์ ํํํ๋ค. (ํด๋น ์ด๋ ธํ ์ด์ ์ ๋ถ์ด๋ฉด ํด๋น ์ธํฐํ์ด์ค๊ฐ ํจ์ํ ์ธํฐํ์ด์ค์์ ๋ณด์ฅํ๋ฉฐ, ์ถ์ ๋ฉ์๋๊ฐ ์์ด์ง๊ฑฐ๋ ๋์ด๋ฌ๋ค๋ ์ง, ํจ์ํ ์ธํฐํ์ด์ค์ ์ ์์ ๋ง์ง ์๊ฒ ๋๋ฉด ์ปดํ์ผ ์๋ฌ๊ฐ ๋ฐ์ํ๊ฒ ๋๋ค.)
๐ฌ ์ถ์ ๋ฉ์๋๋?
์ถ์ ๋ฉ์๋์ ์ ์์ ๋ํด์ ํท๊ฐ๋ฆด ์๋ ์๋ค. ์ถ์ ๋ฉ์๋๋, ์์ ํด๋์ค์์ ๋ฐ๋์ ์ค๋ฒ๋ผ์ด๋ฉ ํด์ผ์ง ์ฌ์ฉํ ์ ์๋ ๋ฉ์๋๋ฅผ ์๋ฏธํ๋ค. ์ฆ, Comparator๋ฅผ ๊ตฌํํ ํด๋์ค๋ ๋ฐ๋์ compare()๋ฅผ ๊ตฌํํด์ผ ํ๋ค.
NaturalOrderComparator implements Comparator<Comparable<Object>> {
@Override
public int compare(Comparable<Object> c1, Comparable<Object> c2) {
return c1.compareTo(c2);
}
Intellij์ ๋์์ ๋ฐ์, Comparator๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ๊ตฌํํ Comparators์ ๊ตฌํ์ฒด์ธ NaturalOrderComparator๋ฅผ ๊ฐ์ ธ์๋ค. (๋ณดํต ์ค๋ฆ์ฐจ์์ผ๋ก ์ ๋ ฌํ ๋ ํด๋น ํด๋์ค๋ฅผ ๋ง์ด ์ฌ์ฉํ๋ค.) ํด๋น ํด๋์ค๋ฅผ ๋ณด๋ฉด ์์ ๊ฐ์ด compare๋ฅผ ๊ตฌํํ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ถ์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ์ด์ ๋, ‘์ค๋ณต๋๋ ๋ถ๋ถ, ๊ณตํต๋๋ ๋ถ๋ถ’์ ๋ฏธ๋ฆฌ ๋ง๋ค์ด์ ธ์๋ ๊ฒ์ ์ฌ์ฉํ๊ณ , ์์ฐํ๋ ์ชฝ์์ ์ด๋ฅผ ๋ฐ์์ ์ฒ๋ฆฌํ ์ ์๋๋ก ํ๊ธฐ ์ํจ์ด๋ค. ์ฆ, ์์ฐํ๋ ์ชฝ์์ ํ๋จํ์ฌ ๋ณธ์ธ์๊ฒ ํ์ํ ๋ถ๋ถ์ ์ฌ์ ์ํ ์ ์๋๋ก ํ๊ธฐ ์ํด์์ด๋ค.
private static class ReverseComparator implements Comparator<Comparable<Object>>, Serializable {
public int compare(Comparable<Object> c1, Comparable<Object> c2) {
return c2.compareTo(c1);
}
์๋ฅผ ๋ค์ด, NaturalOrderComparator์ ๊ฒฝ์ฐ ์์ ๊ฐ์ด ์ธ์๋ก ๋ค์ด์จ c1, c2 ์์ผ๋ก ๋ ๊ฐ์ ๋น๊ตํ์ง๋ง, ReverseComparator์ ๊ฒฝ์ฐ c2, c1 ์์ผ๋ก ๊ฐ์ ๋น๊ตํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์, ๋ค์ ๋์์์ ์ถ์ ๋ฉ์๋๋ abstract ํค์๋๋ฅผ ๋ถ์ด๋ฉฐ, ๋์ ์ธ๋ฏธ์ฝ๋ก (;)์ ๋ถ์ด๋ ๊ฒ์ด ๊ด์ต์ด๋ค. ๊ทธ๋ฌ๋ ์ธํฐํ์ด์ค์์๋ abstract๋ฅผ ์๋ตํ ์ ์์ผ๋ฉฐ, ์ธํฐํ์ด์ค์ ๋ชจ๋ ๋ฉ์๋๋ ‘์ถ์ ๋ฉ์๋’๋ผ๊ณ ์๊ฐํ๋ฉด ๋๋ค.
๊ทธ๋ฌ๋ฉด, ์ฌ๊ธฐ์ ํด์ฆ! Child ์ธํฐํ์ด์ค๋ ํจ์ํ ์ธํฐํ์ด์ค๋ผ๊ณ ํ ์ ์์๊น?
public interface Parent {
int hello(int a, int b);
}
public interface Child extends Parent{
int hello(double a, double b);
}
→ ๋ก! Child ์ธํฐํ์ด์ค๋ฅผ ์์๋ฐ์ผ๋ฉฐ ๋ฐ์ hello(int a, int b);์ ์ํด์ ์ถ์ ๋ฉ์๋๊ฐ 2๊ฐ๊ฐ ๋๊ธฐ ๋๋ฌธ์ ํจ์ํ ์ธํฐํ์ด์ค๋ผ๊ณ ํ ์ ์๋ค.
โ๏ธ ํจ์ํ ์ธํฐํ์ด์ค… ์ ์ฐ๋ ๊ฑด๋ฐ?
์์ ๊ณ์ ๋งํ 'ํจ์ํ ์ธํฐํ์ด์ค'๋ผ๋ ๋จ์ด๋ก ์ธํด์ ์ฌ์ฌ ์ด์ง๋ฌ์์ง๊ธฐ ์์ํ๋ค. ํจ์ํ ์ธํฐํ์ด์ค๋, “์ถ์ ๋ฉ์๋๊ฐ 1๊ฐ์ธ ์ธํฐํ์ด์ค๋ ํจ์ํ ์ธํฐํ์ด์ค”์ด๋ค. ์ฐ๋ฆฌ๋ ์ด ๋ฌธ์ฅ์์ “์ถ์ ๋ฉ์๋๊ฐ 1๊ฐ”๋ผ๋ ๊ฒ์ ์ฃผ๋ชฉํด์ผ ํ๋ค. ๋๋ค ํํ์์ ํตํด, ์ด๋ฌํ ํจ์ํ ์ธํฐํ์ด์ค์ ์ธ์คํด์ค๋ฅผ ์ฝ๊ฒ ๊ตฌํํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค!
๊ฐ๋จํ๊ฒ Runnable ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํด๋ณด์.
// ์ต๋ช
ํด๋์ค๋ฅผ ์ฌ์ฉํ์ ๊ฒฝ์ฐ
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("Anonymous class");
}
};
// ๋๋ค๋ฅผ ์ฌ์ฉํ์ ๊ฒฝ์ฐ
Runnable r2 = () -> System.out.println("Lambda");
Runnable<T>์ run()์ด๋ผ๋ ์ถ์ ๋ฉ์๋๋ฅผ 1๊ฐ๋ง ๊ฐ์ง๊ณ ์๋ ํจ์ํ ์ธํฐํ์ด์ค์ด๋ค. ์ต๋ช ํด๋์ค๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ฉด, ์์ ๊ฐ์ด Runnable ์ธํฐํ์ด์ค์ ๋ํ ๊ตฌํ์ฒด๋ฅผ ์์ฑํ์ง ์๊ณ ๋ ํ๋ผ๋ฏธํฐ ๋ด์์ ๋ฐ๋ก ์ ๋ฌํด์ค ์ ์๋ค. ์ด๋, ๋ด๋ถ์ ๋ฉ์๋๊ฐ ๋ฑ 1๊ฐ์์ ๋ณด์ฅํ๊ธฐ ๋๋ฌธ์ ๋๋ค๋ฅผ ์ฌ์ฉํด์ '๋์ ์์ฒด'๋ง ์ ๋ฌํ ์ ์๋๋ก ๋ณ๊ฒฝํ ์ ์๊ฒ ๋๋ค! ๐
์ด๋, ์ฐ๋ฆฌ๋ ์ด๋ฌํ ๋๋ค ํํ์์ ์๊ทธ๋์ฒ๋ฅผ ํํํ๊ธฐ ์ํด์ 'ํจ์ ๋์คํฌ๋ฆฝํฐ'๋ผ๋ ๋ณ๋์ ์ฉ์ด๋ฅผ ์ฌ์ฉํ ์ ์๋ค. ์์ ๋งํ ๊ฒ์ฒ๋ผ, ํจ์ํ ์ธํฐํ์ด์ค์ ์ถ์ ๋ฉ์๋๋ ๋๋ค ํํ์์ผ๋ก ๋ง๋ค ์ ์๊ธฐ ๋๋ฌธ์, ์ฐ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ด ์ ์ํ ์ ์๋ค.
๐ก ํจ์ํ ์ธํฐํ์ด์ค์ ์๊ทธ๋์ฒ๋ ๋๋ค ํํ์์ ์๊ทธ๋์ฒ์ ๋์ผํ๋ค.
์ฐ๋ฆฌ๋ ์ด๋ฌํ ์๊ทธ๋์ฒ์ ๋ํด์ 'ํจ์ ๋์คํฌ๋ฆฝํฐ'๋ผ๊ณ ๋งํ ์ ์๋ค.
์ฌ๊ธฐ์ ์๊ทธ๋์ฒ๋, ๋ฉ์๋๋ช ๊ณผ ํ๋ผ๋ฏธํฐ์ ์์, ํ์ , ๊ฐ์๋ฅผ ์๋ฏธํ๋ค. (๋ฆฌํด ํ์ , ์์ธ๋ ์ ์ธํ๋ค!)
// ๋๋ค ํํ์ : () -> {}
// ์ด๋, ์๊ทธ๋์ฒ๋ () -> void
execute(() -> {});
public void execute(Runnable r) {
// ์ถ์ ๋ฉ์๋
// ์ด๋, ์๊ทธ๋์ฒ๋ () -> void
r.run();
}
์ฝ๋๋ฅผ ์ดํด๋ณด์. ์ ์ฝ๋์์ ๋๋ค ํํ์์ ์๊ทธ๋์ฒ๋ () -> void, ์ถ์ ๋ฉ์๋์ ์๊ทธ๋์ฒ ์ญ์ () -> void์ด๋ค.
โ๏ธ ์คํ ์ด๋ผ์ด๋ ํจํด
์๋ฐ7์์๋ถํฐ ์ถ๊ฐ๋ Try-with-resources๋ฅผ ํ์ฉํ๋ฉด try์ ์์ ๊ฐ์ฒด๋ฅผ ์ ๋ฌํ๊ณ , try ์ฝ๋ ๋ธ๋ก์ด ๋๋๋ฉด ์๋์ผ๋ก ์์์ ์ข ๋ฃํด์ค ์ ์๋ค. ์ฆ, ๋ชจ๋ catch ๋ธ๋ก์ ๋ณ๋์ ์ข ๋ฃ ์ฒ๋ฆฌ๋ฅผ ํ๊ฑฐ๋, finally ๋ธ๋ก์ ์ ์ธํ์ง ์์๋ ๋๋ค. ์ด์ ๊น์ง๋ ํญ์ ์์์ ์์ฑํ๊ณ , ์ฌ์ฉํ๊ณ , ํด์ ํ ๋์๋ ์๋์ ๊ฐ์ด ์ค๋ณต๋๋ ์ฝ๋๊ฐ ํ์ํ์๋ค.
Resource resource = null;
try {
resource = getResource();
// ๋ฆฌ์์ค ์ฌ์ฉ ๋ก์ง
} catch (...) {
... // ์์ธ ์ฒ๋ฆฌ ๋ก์ง
} finally {
if (resource != null) {
try {
resource.close(); // ์์ ํ ๋น ํด์
} catch (Exception ignored) {
}
}
}
์์ ํด์ ๋ฅผ ์ํด์, ๋ค์๊ณผ ๊ฐ์ด ์ค๋ณต๋๋ try-catch ๋ฌธ์ด ํ์ํ๋ ๊ฒ์ด๋ค. ๊ทธ๋ฌ๋, ์๋ฐ 7์์๋ try-with-resources๋ผ๋ ํน์ง์ด ์ถ๊ฐ๋์ด, try์ ์์์ ์ ๋ฌํ๊ฒ ๋๋ฉด finally์์ ์ข ๋ฃ ์ฒ๋ฆฌ๋ฅผ ํ์ง ์์๋ ์๋์ผ๋ก ์์์ ์ข ๋ฃํด์ฃผ๊ฒ ๋ ๊ฒ์ด๋ค.
try (Resource resource = getResource()) {
// ๋ฆฌ์์ค ์ฌ์ฉ
} catch(...) {
...
}
์์ ๊ฐ์ด ์ฝ๋๊ฐ ํจ์ฌ ๊ฐ๊ฒฐํด์ง๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ฐ๋ฆฌ๋ ์์ ๊ฐ์ ๊ณผ์ ์ ์ด์ '์คํ ์ด๋ผ์ด๋ ํจํด'์ด๋ผ๊ณ ๋งํ ๊ฒ์ด๋ค. ๊ทธ๋ฆฌ๊ณ , ์ด๋ฌํ ์คํ ์ด๋ผ์ด๋ ํจํด์ ๊ตฌํํ๊ธฐ ์ํด์ ๋๋ค์ ๋์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๋ค. ๋ฒ์จ๋ถํฐ ๋ง์ด ๋๋ฌด ์ด๋ ต๋ค. ์ฝ๊ฒ ์ค๋ช ํ๋ฉด, ์ค์ ์์์ ์ฒ๋ฆฌํ๋ ๋ก์ง์, ์ค์ + ์ ๋ฆฌ ๊ณผ์ ์ผ๋ก ๊ฐ์ธ๋ ๊ฒ์ ์๋ฏธํ๋ค.
๐ก ์ฆ, ์คํ ์ด๋ผ์ด๋ ํจํด์ด๋ (์ด๊ธฐํ/์ค๋น) → ์์ ์ฒ๋ฆฌ! → (์ ๋ฆฌ/๋ง๋ฌด๋ฆฌ) ์ด๋ค.
์ค์ ๋ก ์ด๋ค ์์ผ๋ก ์คํ ์ด๋ผ์ด๋ ํจํด์ ์ ์ฉํ ์ ์๋์ง ์ฝ๋๋ฅผ ํตํด์ ์ดํด๋ณด์.
public String processFile() throws IOException {
try (BufferedReader br =
new BufferedReader(new FileReader("data.txt"))) {
return br.readLine();
}
}
BufferedReader๋ฅผ ํตํด ํ์ผ์ ํ ์ค์ ์ฝ๋ ์ฝ๋์ด๋ค. ์ ์ฝ๋๋ฅผ ์ฐจ๋ก๋๋ก ๋ณํ์์ผ๊ฐ๋ฉฐ ์์๋ณด์.
๐ฌ ์ง๊ธ์ ๊ณ ์ ํ ์ค ์ฝ๊ณ ๋๋ด๋๋ฐ, ๋๋ ํ ๋ฒ์ 10์ค์ ์ฝ๋ ์ฝ๋๋ฅผ ๊ตฌํํด ์ฃผ์ธ์.
: ์ฐ๋ฆฌ๊ฐ ์ด๋ฌํ ์๊ตฌ์ฌํญ์ ๋ฐ์์ ๋ ๊ธฐ์กด์ ์ฝ๋์์ ์ด๋ค ๊ฑธ ์๊ฐํ ์ ์์๊น?
1. ์ด๋ฏธ ํ์ผ์ ์ ๊ทผํ๋ ๋ถ๋ถ์ ์๋ค.
2. ๊ฐ์ ์ฝ์ด์ค๊ธฐ ์ํ Reader๋ ์ค๋น๋์ด ์๋ค.
3) 1์ค์ด ์๋, 10์ค์ ์ฝ๋๋ก ํ๋ ๋ก์ง์ด ํ์ํ๋ค.
์ฐ๋ฆฌ๋, BufferedReader๋ฅผ ํตํด 10์ค์ ์ฝ๋๋ก ๋ง๋ค๊ธฐ ์ํด, processFile() ๋ฉ์๋์๊ฒ ๋์์ ์ ๋ฌํด์ฃผ๋๋ก ์์ ํ ๊ฒ์ด๋ค. ๋์์ ์ ๋ฌํด์ฃผ๋ ๊ฒ, ์ฆ ‘๋์ ํ๋ผ๋ฏธํฐํ’๋ฅผ ์ด์ฉํ์๋ ๊ฒ์ด๋ค.
// ์ฐ๋ฆฌ๋ ์ด๋ ๊ฒ ๋์ํ ์ ์๋๋ก ๋ง๋ค๊ณ ์ถ๋ค.
String result =
processFile((BufferedReader br) -> {
StringBuilder fileMessage = new StringBuilder();
for (int i = 0; i < 10; i++) {
fileMessage.append(br.readLine());
}
return fileMessage.toString();
};
์ฐ๋ฆฌ๋ ๋๋ค๋ฅผ ํ์ฉํ์ฌ ๋ค์๊ณผ ๊ฐ์ด 10์ค์ ๋ฐ์์ ์ฒ๋ฆฌํ๋๋ก ๋ง๋ค์๋ค. (์ฒ์๋ถํฐ ๋๋ค ํํ์์ ๋ง๋ค์๋ค๊ธฐ๋ณด๋จ, 10์ค์ ์ฒ๋ฆฌํ๋ ๋์ ์์ฒด๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋๊ฒผ๋ค๊ณ ๋ณด๋ ๊ฒ์ด ๋ ์ฝ๋ค.) processFile()์ ์ธ์๋ก 10์ค์ ์ฝ๋ ๋์ ์์ฒด๋ฅผ ์ ๋ฌํด์ค ๊ฒ์ด๋ค. ์ด๋ ๊ฒ ๋ง๋ ๋์ ์์ฒด๋ฅผ ํ๋ผ๋ฏธํฐํ ์์ผฐ๋ค๋ฉด, ์ด์ ์ด๋ฅผ ๋ฐํ์ผ๋ก ํจ์ํ ์ธํฐํ์ด์ค๋ฅผ ํ๋ ์ ์ธํด๋ณด์.
@FunctionalInterface
public interface BufferedReaderProcessor {
String process(BufferedReader b) throws IOException;
}
๋๋ค ํํ์์ ์๊ทธ๋์ฒ์ ์ถ์ ๋ฉ์๋์ ์๊ทธ๋์ฒ๋ ๋์ผํ๊ธฐ ๋๋ฌธ์, ํ๋ผ๋ฏธํฐ๋ก BufferedReader๋ฅผ ์ ์ธํด์ค๋ค. (๋ฉ์๋๋ช ์ ์ต๋ช ํจ์์ด๊ธฐ ๋๋ฌธ์ ๋ณ๋๋ก ๊ณ ๋ คํ์ง ์์๋ ๋๋ค.) ์ด์ , ์ด๋ฌํ process() ๋ฉ์๋์ ์๊ทธ๋์ฒ์ ๋์ผํ ๋๋ค๋ฅผ ์ ๋ฌํด๋ณด์.
public String processFile(BufferedReaderProcessor p) throws IOException {
try (BufferedReader br =
new BufferedReader(new FileReader("data.txt"))) {
return p.process(br); // ์ด๋ ๊ฒ ์ฒ๋ฆฌํ ์ ์๊ฒ ๋์๋ค!
}
}
์ฝ๋๋ฅผ ๋ณด๋ฉด, ์ธ์๋ก BufferedReaderProcessor๋ผ๋ ํจ์ํ ์ธํฐํ์ด์ค๋ฅผ ๋ฐ๋ ๊ฒ์ ๋ณผ ์ ์๋ค. ์ด๋ ๊ฒ ๋ฐ์ ํจ์ํ ์ธํฐํ์ด์ค์ process() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์ค์ ๋์์ ์คํํ ์ ์๋๋ก ๋ง๋ค์๋ค. ์ด์ , ์ฐ๋ฆฌ๋ ํจ์ํ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ค์ ํ ๋ฒ ๋์ผํ ์๊ทธ๋์ฒ๋ฅผ ๊ฐ์ง ๋๋ค ํํ์์ผ๋ก ๋ณ๊ฒฝํ ์ ์๋ค.
// 10์ค ์ฝ๊ธฐ
String tenLine =
processFile((BufferedReader br) -> {
StringBuilder fileMessage = new StringBuilder();
for (int i = 0; i < 10; i++) {
fileMessage.append(br.readLine());
}
return fileMessage.toString();
};
// 1์ค ์ฝ๊ธฐ
String oneLine =
processFile((BufferedReader br) -> br.readLine());
์ต์ข ์ ์ผ๋ก ์ ๋ฆฌํ ์ฝ๋๋ฅผ ๋ณด๋ฉด, ๋์ ์์ฒด๋ฅผ ๋๋ค ํํ์์ผ๋ก ์ ๋ฌํ์ฌ 10์ค๋ก ์ฝ๋ , 1์ค๋ก ์ฝ๋ ์์ ๋กญ๊ฒ ๋ง๋ค ์ ์๊ฒ ๋์๋ค. ์คํ ์ด๋ผ์ด๋ ํจํด์ ํ์ฉํ์ฌ, ์ค์ ๋ก ๋์์ ์ฒ๋ฆฌํ๋ ๋ถ๋ถ์ ๋ํด์ ํ๋ผ๋ฏธํฐ๋ก ๋๊ฒจ, ๋๋ค ํํ์์ ํ์ฉํด ๋ ๊ฐ๊ฒฐํ๊ฒ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๊ฒ ๋์๋ค. ์๋ ์ฝ๋๋, ์ด๋ค ๊ณผ์ ์ผ๋ก ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ๋์ง ์ ๋ฆฌํ๋ ๋ถ๋ถ์ด๋ค.
// Step 1 - return์์ ๋ฐ๋ก ๋ก์ง์ ์ ์ธํ๊ธฐ ๋๋ฌธ์ ํ์ฅ์ฑ์ด ์๋ค.
public String processFile() throws IOException {
try (BufferedReader br =
new BufferedReader(new FileReader("data.txt"))) {
return br.readLine();
}
}
// Step 2 - ํจ์ํ ์ธํฐํ์ด์ค ์ ์ธํ๊ธฐ
@FunctionalInterface
public interface BufferedReaderProcessor {
String process(BufferedReader b) throws IOException;
}
// ๊ธฐ์กด์ ์ฝ๋์์ ์๊ทธ๋์ฒ๋ฅผ ๋ง์ถฐ์ค๋ค.
public String processFile(BufferedReaderProcessor p) throws IOException {
...
}
// step 3 - ๋ด๋ถ ๊ตฌํ ๋ก์ง์ ๊ฐ์๋ผ์ธ ์ ์๋๋ก ๋ง๋ค๊ธฐ.
public String processFile(BufferedReaderProcessor p) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
return p.process(br);
}
}
// step 4 - ๋๋ค๋ก ๋ณ๊ฒฝํ๊ธฐ!
String tenLine =
processFile((BufferedReader br) -> {
StringBuilder fileMessage = new StringBuilder();
for (int i = 0; i < 10; i++) {
fileMessage.append(br.readLine());
}
return fileMessage.toString();
};
// 1์ค ์ฝ๊ธฐ
String oneLine =
processFile((BufferedReader br) -> br.readLine());
โ๏ธ ํจ์ํ ์ธํฐํ์ด์ค ์์ฉํ๊ธฐ
๋ด์ฉ์ด ๋ง์์ ํท๊ฐ๋ฆฌ๋ ๋ถ๋ถ์ด ๋ง์ ์๋ฐ์ ์๋ค. ๊ฐ๋ณ๊ฒ ํ ๋ฒ ์ ๋ฆฌํด๋ณด์.
โ๏ธ ํจ์ํ ์ธํฐํ์ด์ค๋ ํ๋์ ์ถ์ ๋ฉ์๋๋ง ๊ฐ์ง๋ค.
โ๏ธ ์ถ์ ๋ฉ์๋๋ ๋๋ค ํํ์์ ์๊ทธ๋์ฒ์ ๋์ผํ๋ค.
โ๏ธ ํจ์ํ ์ธํฐํ์ด์ค์ ์ถ์ ๋ฉ์๋ ์๊ทธ๋์ฒ๋ฅผ ํจ์ ๋์คํฌ๋ฆฝํฐ๋ผ๊ณ ํ๋ค.
์๋ฐ์์๋ ์ด๋ฌํ ํจ์ํ ์ธํฐํ์ด์ค๋ฅผ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ช ๊ฐ์ง ์ ๊ณตํ๋ค. java.util.function ํจํค์ง์ ์กด์ฌํ๋ฉฐ, ๋ช ๊ฐ์ง ํจ์ํ ์ธํฐํ์ด์ค๋ฅผ ๊ฐ๋จํ๊ฒ ์ดํด๋ณด์.
๐ฌ Predicate
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
public <T> List<T> filter(List<T> list, Predicate<T> p) {
List<T> results = new ArrayList<>();
for (T t : list) {
if (p.test(t)) {
results.add(t);
}
}
return results;
}
// Example
Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);
Predicate<T>๋ test()๋ผ๋ ์ถ์ ๋ฉ์๋๋ฅผ ์ ์ํ๊ณ , ์ธ์๋ก ๋ฐ์ ์ ๋ค๋ฆญ ํ์ T๋ฅผ ์ฒ๋ฆฌํ์ฌ boolean ๊ฐ์ผ๋ก ๋ฐํํ๋ ๊ฒ์ด ํน์ง์ด๋ค. ์ฃผ๋ก ์ฐธ/๊ฑฐ์ง์ ๋ํ ํ๋จ์ ์ด์ฉํ ๋ ๋ง์ด ์ฌ์ฉํ๋ค.
๐ฌ Consumer
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
public <T> void forEach(List<T> list, Consumer<T> c) {
for (T t : list) {
c.accept(t);
}
}
// example
forEach(
Arrays.asList(1,2,3,4,5),
(Integer i)->System.out.println(i));
Consumer<T>๋ accept()๋ผ๋ ์ถ์ ๋ฉ์๋๋ฅผ ์ ์ํ๋ฉฐ, ์ธ์๋ก ๋ฐ์ T ํ์ ์ ํตํด ์ด๋ ํ ๋์์ ์ํํ๋๋ก ๋ง๋ ๋ค. ์ด๋, ๋ฆฌํด๊ฐ์ด ์๊ธฐ ๋๋ฌธ์ ๋์์ ๋ํ ์คํ ๋ก์ง์ ์ ์ํ ๋ ํ์ฉํ๊ธฐ ์ข๋ค.
๐ฌ Function
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
public <T, R> List<R> map(List<T> list, Function<T, R> f) {
List<R> result = new ArrayList<>();
for (T t : list) {
result.add(f.apply(t));
}
return result;
}
// example
List<Integer> l = map(
Arrays.asList("lambdas","in","action"),
(String s)->s.length() // [7, 2, 6]
);
Function<T, R> ์ apply()๋ผ๋ ์ถ์ ๋ฉ์๋๋ฅผ ์ ์ํ๋ฉฐ, ์ธ์๋ก ๋ฐ์ T ํ์ ์ ํตํด R ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค. ์ ๋ ฅ → ์ถ๋ ฅ์ผ๋ก ์ด๋ ํ ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์ ์ฉํ๋ค.
์ฐธ๊ณ ๋ก, ์ด๋ฌํ ํจ์ํ ์ธํฐํ์ด์ค ๋ด๋ถ์ ์ ๋ค๋ฆญ ํ๋ผ๋ฏธํฐ๋ ๋ฌด์กฐ๊ฑด ๋ ํผ๋ฐ์ค ํ์ ๋ง ์ฌ์ฉํ ์ ์๋๋ฐ, ์ด๋ ์๋ฐ์์๋ primitive ํ์ ์ ๋ ํผ๋ฐ์ค ํ์ ์ผ๋ก ๋ณํํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค. ์ด๋ฅผ ‘๋ฐ์ฑ(Boxing)’์ด๋ผ๊ณ ํ๊ณ , ๋ฐ๋์ ๊ณผ์ ์ ‘์ธ๋ฐ์ฑ(Unboxing)’์ด๋ผ๊ณ ํ๋ค. ๋ณดํต ์๋ฐ์์๋, ๋ฐ์ฑ๊ณผ ์ธ๋ฐ์ฑ์ ์๋์ผ๋ก ์ฒ๋ฆฌํด์ฃผ๋ ์คํ ๋ฐ์ฑ(autoboxing)์ด ๋ง์ด ์ฌ์ฉ๋๋๋ฐ, ํํ ๋ฆฌ์คํธ์ ๊ฐ์ ๋ฃ์ ๋ ๋ด๋ถ ์์๋ wrapping ๋์ด ๋ค์ด๊ฐ๋ค.
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
// int -> Integer๋ก autoboxing ๊ณผ์ ์ด ์ผ์ด๋๋ค.
list.add(i);
}
// ArrayList.java
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
๊ถ๊ธํด์ ์ฐพ์๋ดค๋๋ฐ, ์ ๋ค๋ฆญ์ผ๋ก ๋ฐ๋ ์์ ๋ถํฐ ๋ ํผ๋ฐ์ค ํ์ ๋ง ๋ฐ์ ์ ์์ผ๋ ์ปดํ์ผ๋ฌ์์ ์์์ wrapping ํด์ค๋ค๊ณ ํ๋จํ์๋ค. ์ด๋ฌํ wrapping ๊ณผ์ ์ ๊ฒฐ๊ตญ ํ์ ์ ์ฅ๋๋ฉด์ ๋ฉ๋ชจ๋ฆฌ ์๋น๊ฐ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์ ์ผ๋ก ์ด์๊ฐ ์์ ์ ์๋๋ฐ, ํจ์ํ ์ธํฐํ์ด์ค๋ฅผ ํ์ฉํ์ฌ ์คํ ๋ฐ์ฑ์ ํผํ ์ ์๊ฒ ๋๋ค.
IntPredicate evenNumbers = (int i) -> i % 2 == 0;
// ์ฌ๊ธฐ์ 1000์ ๋ฐ์ฑํ์ง ์๋๋ค. ์คํ ๋ฐ์ฑ์ ํผํ ์ ์๋ค.
evenNumbers.test(1000);
Predicate<Integer> oddNumbers = (Integer i) -> i % 2 != 0;
// Predicate<Integer>์์๋ 1000์ด๋ผ๋ ๊ฐ์ Integer๋ก ๋ฐ์ฑํ๊ฒ ๋๋ค.
oddNumbers.test(1000);
์ ์ฝ๋์์ ์ฌ์ฉํ๋ IntPredicate๋ฅผ ์ด์ฉํ๊ฒ ๋๋ฉด, primitive ํ์ ์ธ int ๊ฐ์ boxing ํ์ง ์์ ์ํ๋ก Predicate<T> ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ ํจ๊ณผ๋ฅผ ์ป์ ์ ์๋ค. IntPredicate ์ธ์๋ ๋ค์ํ ํ์ ์ ๋ง๋ Predicate๊ฐ ์กด์ฌํ๊ธฐ ๋๋ฌธ์ ์ํฉ์ ๋ฐ๋ผ์ ๋ง์ถฐ์ ์ฌ์ฉํ๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค.
์๋๋ ์๋ฐ์์ ์ ๊ณตํ๋ ํจ์ํ ์ธํฐํ์ด์ค์ ๋์คํฌ๋ฆฝํฐ ์ ๋ณด์ด๋ค. (๋ฌผ๋ก ๋ ๋ง์ด ์๋ค!)
ํจ์ํ ์ธํฐํ์ด์ค ์ด๋ฆ | ํจ์ ๋์คํฌ๋ฆฝํฐ |
Predicate<T> | T -> boolean |
Consumer<T> | T -> void |
Function<T, R> | T -> R |
Supplier<T> | () -> T |
UnaryOperator<T> | T->T |
BinaryOperator<T> | (T, T) -> T |
BiPredicate<L, R> | (T, U) -> boolean |
BiConsumer<T, U> | (T, U) -> void |
BiFunction<T, U, R> | (T, U) -> R |
๐ฌ ์ถ๊ฐ์ ์ผ๋ก, ํจ์ํ ์ธํฐํ์ด์ค์์๋ Checked Exception์ ๋์ง์ง ์๋๋ค. ๊ต์ฌ์์๋ ๋จ์ํ ์์ธ๋ฅผ ๋์ง ์ ์๋ค๊ณ ๋์์, ๋ฌด์จ ๋ง์ธ์ง ์ดํด๊ฐ ์ ๋์๋๋ฐ, ์ ํํ๊ฒ ๋งํ๋ฉด ์๋ฐ์์ ์ ๊ณตํ๋ ๊ธฐ๋ณธ ํจ์ํ ์ธํฐํ์ด์ค์ ์ถ์ ๋ฉ์๋์ ๋ํด์ ๋ณ๋๋ก Exception์ throw ํ์ง ์๋๋ค๋ ๋ง์ด์๋ค. ๊ทธ๋์, ๊ฐ๋ฐ์๊ฐ ์ง์ ์์ธ๋ฅผ ๋์ง๊ธฐ ์ํด์๋ ์ปค์คํ ์ธํฐํ์ด์ค๋ฅผ ์ ์ํด์ ๋ช ์์ ์ผ๋ก throws์ ํตํด ์ ํ์ํค๊ฑฐ๋, ๋๋ค ์์ฒด๋ฅผ try - catch๋ก ์ก์์ runtime Exception์ผ๋ก ๊ฐ์ธ์ ์ฒ๋ฆฌํด์ค์ผ ํ๋ค. (์ฌ์ค, ์ด๋ checked exception์ ๊ฐ๋ ์์ฒด์์ ๋์ค๋ ๋ฌธ์ ๊ฐ ์๋๊ฐ ์ถ๊ธฐ๋ ํ๋ค.)
1) throws๋ก ์์ธ ์ ํํ๊ธฐ
@FunctionalInterface
public interface BufferedReaderProcessor {
String process(BufferedReader b) throws IOException;
}
BufferedReaderProcessor p = (BufferedReader br) -> br.readLine();
2) try-catch๋ก ์ก์์ ์ฒ๋ฆฌํ๊ธฐ
Function<BufferedReader, String> f = (BufferedReader b) -> {
try {
return b.readLine();
} catch (IOException e) {
throw new RuntimeException(e);
}
};
โ๏ธ ๋๋ค ํํ์์ ์ด๋ป๊ฒ ๊ตฌํ์ฒด์ ์ ๋ณด๋ฅผ ์๊น์?
๋๋ค ํํ์์ ๋๋ค๊ฐ ์ฌ์ฉ๋๋ ์ปจํ ์คํธ๋ฅผ ์ด์ฉํ์ฌ ๋๋ค์ ํ์์ ์ถ๋ก ํ ์ ์๋ค. ์ด๋, ๋๋ค์๊ฒ ์ ๋ฌ๋๋ ํ๋ผ๋ฏธํฐ๋ ๋ณ์ ๋ฑ ๋๋ค์์ ์ฌ์ฉ๋๊ธฐ๋ฅผ ๊ธฐ๋ํ๋ ํํ์์ ํ์์ ‘๋์ ํ์’์ด๋ผ๊ณ ํ๋ค.
List<Crew> crews = filter(wootecho, (Crew crew) ->
crew.getCourse().equals(BACKEND));
์ ์์ ๋ ์ฐํ ์ฝ ํฌ๋ฃจ๋ค ์ค์์ ๋ฐฑ์๋์ธ ํฌ๋ฃจ๋ค๋ง ๋ฝ๋ ์์ ์ด๋ค. ์ ์ฝ๋์์ ๋๋ค ํํ์์ ์ด๋ป๊ฒ ํ์ ๊ฒ์ฌ๋ฅผ ์งํํ๋์ง ์์๋ณด์.
1) filter ๋ฉ์๋์ ์ ์ธ ํ์ธํ๊ธฐ
// filterCrews์ ์ ์
public List<Crew> filterCrews(List<Crew> crews, Predicate p) {
List<Crew> resultCrews = new ArrayList<>();
for (Crew crew : crews) {
if (p.test(crew) {
resultCrews.add(crew);
}
}
}
// before
filterCrews(wootecho, (Crew crew) → crew.getCourse().equals(BACKEND))
// after
filterCrews(wootecho, Predicate<Crew> p)
ํ์ฌ, ์ ์ฝ๋์์ filterCrews()๋ ๋ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก Predicate<Crew> ํ์์ ๊ธฐ๋ํ๋ค. ์ฌ๊ธฐ์ Predicate<Crew>๊ฐ ๋์ ํ์์ด ๋๋ค.
2) Predicate<Crew>์ ์๊ทธ๋์ฒ์ ๋ํด์ ์ดํด๋ณด๊ธฐ
์๋ฐ์์ ๊ธฐ๋ณธ์ผ๋ก ์ ๊ณต๋๋ Predicate<T> ํจ์ํ ์ธํฐํ์ด์ค๋, test()๋ผ๋ ์ถ์ ๋ฉ์๋๋ฅผ ๊ฐ์ง๋ค. ์ด๋, ํด๋น ์ถ์ ๋ฉ์๋์ดใ ก ์๊ทธ๋์ฒ๋ T -> boolean์ด๋ฉฐ, ์ ์์ ์์๋ Crew -> boolean์ด ๋๋ค.
3) ํจ์ ๋์คํฌ๋ฆฝํฐ ๋ฌ์ฌํ๊ธฐ
์ด๋, Crew๋ฅผ ์ธ์๋ก ๋ฐ์ boolean์ ๋ฐํํ๋ ํจ์ ๋์คํฌ๋ฆฝํฐ๋ฅผ ๋ฌ์ฌํ๊ฒ ๋๋ฉฐ, ์ด ๊ณผ์ ์์ ๋๋ค ํํ์์ด ์์ธ๋ฅผ ๋์ง ์ ์๋ค๋ฉด ์ถ์ ๋ฉ์๋์์๋ ์์ธ๋ฅผ ๋์ง ์ ์๋๋ก throws๋ก ๋์ง๊ฑฐ๋, try-catch๋ก ์ก์ ์ฒ๋ฆฌํด์ผ ํ๋ค. ์๋ฌดํผ, filter๋ก ์ ๋ฌ๋๋ ์ธ์๋ ์์ ๊ฐ์ ์๊ตฌ์ฌํญ์ ๋ง์กฑํด์ผ ํ๋ฉฐ, ํ์ฌ ์ฝ๋์์๋ (Crew crew) -> crew.getCourse.equals(BACKEND); ๋ผ๋ ์ฝ๋ ์์ฒด๊ฐ Crew -> boolean์ ๋ฐํํ๊ณ ์์ด์
๐ฌ ์ด๋, '๋์ ํ์'์ด๋ผ๋ ํน์ง ๋๋ฌธ์, ๋๋ค์๋ง๋ค ๊ทธ์ ํธํํ๋ ์ถ์ ๋ฉ์๋๋ฅผ ๊ฐ์ง ๋ค๋ฅธ ํจ์ํ ์ธํฐํ์ด์ค๋ก ์ฌ์ฉ๋ ์ ์๋ค.
Comparator<Crew> c1 =
(Crew a1, Crew a2) -> a1.getAge().compareTo(a2.getAge());
ToIntBiFunction<Crew, Crew> c2 =
(Crew a1, Crew a2) -> a1.getAge().compareTo(a2.getAge());
BiFunction<Crew, Crew, Integer> c3 =
(Crew a1, Crew a2) -> a1.getAge().compareTo(a2.getAge());
์์ ์ธ ์ฝ๋ ๋ชจ๋ Crew๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์, compareTo๋ฅผ ํตํด์ ๋น๊ตํ ๊ฒฐ๊ณผ๋ฅผ ๋ด์ง๋ง (๋์ผํ ๋๋ค์์ด์ง๋ง) ๊ฐ๊ฐ ๋ค๋ฅธ ํจ์ํ ์ธํฐํ์ด์ค๊ฐ ์ฌ์ฉ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
๐ฌ ๋๋ค์ void ํธํ ๊ท์น
๋๋ค์ ๋ฐ๋์ ์ผ๋ฐ ํํ์์ด ์์ผ๋ฉด, void๋ฅผ ๋ฐํํ๋ ํจ์ ๋์คํฌ๋ฆฝํฐ์ ํธํ๋๋ค.
// Predicate๋ ๋ถ๋ฆฌ์ธ ๋ฐํ๊ฐ์ ๊ฐ๋๋ค. (์ถ๊ฐํ ๋ค ์ฌ๋ถ ๋ฐํ)
Predicate<String> p = s -> list.add(s);
// Consumer๋ void ๋ฐํ๊ฐ์ ๊ฐ๋๋ค. (์ถ๊ฐํ๋ ๊ฒ์ ๋ํ ํ์)
Consumer<String> b = s -> list.add(s);
list.add()๋ ์๋ ๋ฐํ๊ฐ์ด boolean์ธ ๋ฉ์๋์ธ๋ฐ, Predicate๋ก๋ ์ฌ์ฉํ ์ ์์ง๋ง ์๋์ ๊ฐ์ด Consumer์์๋ ์ฌ์ฉํ ์ ์๋ ๊ฒ์ ๋ณผ ์ ์๋ค. (์ฌ๊ธฐ์ ์ผ๋ฐ ํํ์์ด๋ผ๋ ๋ง์ด ๊ต์ฅํ ๋ชจํธํ๋ฐ, ๊ธฐ๋ณธ์ ์ผ๋ก ์๋ฐ๋ ๋ฉ์๋์ ๋ฆฌํด๊ฐ์ ์ฌ์ฉํ์ง ์์๋ ๋๋ค. ๊ทธ๋์ ์ ์์ ์์๋ ๋ฆฌํด๊ฐ์ ์ฌ์ฉํ์ง ์์ ์ ์์ผ๋ void๋ฅผ ๋ฐํํ๋ Consumer์ ์ฌ์ฉํ๊ฒ ๋๋ฉด, ๋จ์ํ ๋์ ์์ฒด๋ง ์คํํ๋ ํํ๋ก ์ฌ์ฉํ๋ ์์ผ๋ก ํ๋ ๊ฒ ์๋๊น... ๋ผ๋ ๊ฒ ๋ด ์๊ฐ์ด๋ค ๐ค)
๐ฌ ํจ์ํ ์ธํฐํ์ด์ค์ ๋ฉ์๋ ์ค๋ฒ๋ผ์ด๋ฉ
// Java์์ ์ ๊ณตํ๋ ํจ์ํ ์ธํฐํ์ด์ค
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
// ๋ด๊ฐ ๋ง๋ ํจ์ํ ์ธํฐํ์ด์ค
@FunctionalInterface
public interface Sample {
void run();
}
์์ ๊ฐ์ ๋ ๊ฐ์ ํจ์ํ ์ธํฐํ์ด์ค๊ฐ ์กด์ฌํ๋ค๊ณ ๊ฐ์ ํด๋ณด์.
public class Main {
public static void main(String[] args) {
execute(() -> {});
}
public static void execute(Runnable runnable) {
runnable.run();
}
public static void execute(Sample sample) {
sample.run();
}
}
์ด๋, () → {}๋ผ๋ ๋์คํฌ๋ฆฝํฐ๊ฐ () → void์ธ ๋๋ค ํํ์์ด ์์ ๋, ์ด๋ค ๊ฑธ ์ฌ์ฉํ๊ฒ ๋ ๊น?
Intellij์์๋ ๋ชจํธํ๋ค๊ณ ์๋ ค์ค๋ค. ์ฆ, ์ด ๊ณผ์ ์์ ๋์ ํ์์ ํตํด ์ปจํ ์คํธ๊ฐ ๋์ผํ ‘ํจ์ํ ์ธํฐํ์ด์ค’๋ฅผ ์ฐพ์๋๊ฐ๋ ๊ฑธ ๋ณผ ์ ์๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์, ๋ช ์์ ์ผ๋ก ์บ์คํ ํ๋ ๊ณผ์ ์ด ํ์ํ๋ค.
public static void main(String[] args) {
execute((Sample) () -> {});
}
๋๋ ๋ด๊ฐ ๋ง๋ ๊ฒ ์ข์ผ๋๊น ์ด๋ ๊ฒ ์บ์คํ ์ ์งํํ๋ค.
๐ฌ ์ ๋ฆฌ
๐ก ์๋ฐ ์ปดํ์ผ๋ฌ๋ ๋๋ค ํํ์์ด ์ฌ์ฉ๋ ์ปจํ ์คํธ (=๋์ ํ์)์ ํตํด, ๋๋ค ํํ์๊ณผ ๊ด๋ จ๋ ํจ์ํ ์ธํฐํ์ด์ค๋ฅผ ์ถ๋ก ํ๋ค.
= ๊ทธ๋ ๊ธฐ ๋๋ฌธ์, ์ปดํ์ผ๋ฌ๋ ๋๋ค์ ์๊ทธ๋์ฒ๊น์ง ์ถ๋ก ์ ํ ์ ์๋ค.
= ์ฆ, ์๊ทธ๋์ฒ๋ฅผ ์๋๊น ๋๋ค์ ๋ฌธ๋ฒ์ ์์ฒด์์๋ ์ด๋ฅผ ์๋ตํ ์ ์๋ค!
โ๏ธ ๋๋ค์์๋ ํ์ ์ ์๋ตํด๋ ๋๋ค๋๋ฐ?
์ฐ๋ฆฌ๋ ์์์ ์ปดํ์ผ๋ฌ๊ฐ ๋๋ค์ ์๊ทธ๋์ฒ๋ฅผ ์๋ค๋ ์ฌ์ค์ ๋์ถํ์๋ค.
// Before
List<Crew> crews = filter(wootecho, (Crew crew) ->
crew.getCourse().equals(BACKEND));
// After
List<Crew> crews = filter(wootecho, crew ->
crew.getCourse().equals(BACKEND));
์ด๋ฐ ์์ผ๋ก, ๊ตณ์ด ๋ช ์์ ์ผ๋ก Crew๋ผ๋ ํ๋ผ๋ฏธํฐ ํ์ ์ ์ง์ ํด์ฃผ์ง ์์๋ ๋๋ ๊ฒ์ ์ ์ ์๋ค. ํนํ, ํ๋ผ๋ฏธํฐ์ ๊ฐ์๊ฐ ๋์ด๋๋ฉด ๊ฐ ํ๋ผ๋ฏธํฐ ๋ชจ๋์๊ฒ ํ์ ์ ์ง์ ํด์ค ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ฝ๋์์ผ๋ก๋ ๋ ๊ฐ๊ฒฐํด์ง๊ฒ ๋๋ค.
์ฆ, ์ ๋ฆฌํ์๋ฉด!
1. ์๋ฐ ์ปดํ์ผ๋ฌ๋ ๋๋ค ํํ์์ด ์ฌ์ฉ๋ ์ปจํ ์คํธ (๋์ ํ์)์ ํตํด ๋๋ค ํํ์๊ณผ ๊ด๋ จ๋ ํจ์ํ ์ธํฐํ์ด์ค๋ฅผ ์ถ๋ก ํ๋ค.
2. ์ด๋ ๊ฒ ์ถ๋ก ํ ํจ์ํ ์ธํฐํ์ด์ค ๋๋ถ์, ํจ์ ๋์คํฌ๋ฆฝํฐ๋ฅผ ์ ์ ์๋ค.
3. ์ฆ, ์ปดํ์ผ๋ฌ๋ ๋๋ค์ ์๊ทธ๋์ฒ๋ฅผ ์ถ๋ก ํ ์ ์๋ค. (์ถ์ ๋ฉ์๋ ์๊ทธ๋์ฒ == ๋๋ค์ ์๊ทธ๋์ฒ)
4. ์ปดํ์ผ๋ฌ๋ ๋๋ค ํํ์์ ํ๋ผ๋ฏธํฐ ํ์์ ์ ๊ทผํ ์ ์๊ธฐ ๋๋ฌธ์, ๋ฌธ๋ฒ์ ์ผ๋ก ์๋ต์ด ๊ฐ๋ฅํ๋ค.
โ๏ธ ๋๋ค์ ์ง์ญ ๋ณ์
๋๋ค์์๋ ์ต๋ช ํจ์์ฒ๋ผ ์ธ๋ถ์์ ์ ์๋ ๋ณ์๋ฅผ ํ์ฉํ ์ ์๋ค. (์ด๋ฅผ ์์ ๋ณ์๋ผ๊ณ ํ๋๋ฐ, ํ๋ผ๋ฏธํฐ๋ก ๋๊ฒจ์ง ๋ณ์๊ฐ ์๋, ์ธ๋ถ์์ ์ ์๋ ๋ณ์ ์์ฒด๋ฅผ ์๋ฏธํ๋ค๊ณ ์๊ฐํ๋ฉด ๋๋ค.) ์ด๋ฅผ ๋๋ค ์บก์ฒ๋ง์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค. ๊ทธ๋ฌ๋, ์ด๋ ํด๋น ์ง์ญ๋ณ์๋ ๋ช ์์ ์ผ๋ก final๋ก ์ ์ธ๋์ด ์๊ฑฐ๋, final์ฒ๋ผ ์ฌ์ฉ๋์ด์ผ ํ๋ค๋ ์ ์ด ํฐ ํน์ง์ด๋ค. (์ธ์คํด์ค, ํด๋์ค, ์ ์ ๋ณ์๋ ์๊ด์๋ค.)
public class Main {
private String pobi = "I'm pobi"; // ์ธ์คํด์ค ๋ณ์
private static String WOOTECO = "I'm Wooteco"; // ํด๋์ค ๋ณ์
private static final String COACH = "I'm Coach"; // ์ ์ ๋ณ์
public void main(String[] args) {
String crew = "I'm Crew"; // ์ง์ญ ๋ณ์, final ์ทจ๊ธ์ด๋ค.
Runnable r1 = () -> System.out.println(crew);
Runnable r2 = () -> System.out.println(COACH);
Runnable r3 = () -> System.out.println(pobi);
Runnable r4 = () -> System.out.println(WOOTECO);
r1.run(); // I'm Crew
r2.run(); // I'm Coach
r3.run(); // I'm pobi
r4.run(); // I'm Wooteco
}
}
๋ง์ฝ, crew์ ๋ค๋ฅธ ์ด๋ฆ์ ํ ๋นํ๋ ค๊ณ ํ๋ค๋ฉด, Intellij์์๋ ๋ค์๊ณผ ๊ฐ์ด ๋๋ค ํํ์์ final์ด์ด์ผ ํ๋ค๊ณ ๊ฒฝ๊ณ ํ๋ค.
๐ฌ ์ ์ด๋ฐ ์ ์ฝ์ ๊ฑด ๊ฑธ๊น?
๊ด๋ จํด์๋ ํ๋กค๋ก๊ทธ์ ๊ธ์ ์์ฑํด๋์๋ค! ๐
์์ฝํ์๋ฉด, ์ธ์คํด์ค ๋ณ์๋ heap, ์ ์ / ํด๋์ค ๋ณ์๋ static ์์ญ์ ์์นํด ์๊ธฐ ๋๋ฌธ์ ๋ชจ๋ ์ค๋ ๋๊ฐ ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ค. ๊ทธ๋ฌ๋, ์ง์ญ๋ณ์๋ ์ค๋ ๋ ๋ณ๋ก ์คํ ์์ญ์ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ๋ผ์ดํ ์ฌ์ดํด ์์ฒด๋ ๋ณ์๊ฐ ์ ์ธ๋ ๋ธ๋ก์ด ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์, ๋ง์ฝ ๋๋ค์์ ๋ณ๋์ ์ค๋ ๋์์ ์คํํ๋ค๋ฉด, ์ฝ๋ ๋ธ๋ก์ด ๋๋ฌ์ ๋ ํด๋น ๋ณ์๋ ์คํ์์ ์ ๊ฑฐ๋์ง๋ง ๋๋ค์์ด ์ํ๋ ๋ ์ฌ์ ํ ํด๋น ๋ณ์๋ฅผ ์ฐธ์กฐํ ์ ์๊ธฐ ๋๋ฌธ์, ์ด๋ฌํ ๊ฐ๋ฅ์ฑ์ ์์ ๊ธฐ ์ํด์ ๋๋ค๋ ๋ณดํต ์ง์ญ ๋ณ์์ ๋ณต์ฌ๋ณธ์ ๊ฐ์ง๊ณ ์๋๋ค. ๋ณต์ฌ๋ณธ์ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ์๋ณธ ๋ณ์์ ๊ฐ์ด ๋ฌ๋ผ์ง๋ฉด ์ ๋๊ธฐ ๋๋ฌธ์, final ํค์๋๋ฅผ ํตํด์ ๋ณ๊ฒฝ ์์ฒด๋ฅผ ๋ง์๋ฒ๋ฆฌ๋ ๊ฒ์ด๋ค.
์ฑํฐ 3์ ๊ฒฝ์ฐ ๋ด์ฉ์ด ๊ต์ฅํ ๊ธธ์ด์ 2๊ฐ๋ก ๋๋ ์ธ ์์ ์ด๋ค.
๊ฐ์ธ์ ์ผ๋ก ๋๋ค ์บก์ณ๋ง์ ๋ํ ๋ด์ฉ์ด ๊ต์ฅํ ์๋ฌ๋๋ค ๐ ์ผ๋ฅธ ๋จ์ ์ฑํฐ๋ ์จ์ผ๊ฒ ๋ค...!