item 46 dodo4513 - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki
- ์คํธ๋ฆผ์ ์ฒ์ ๋ด์๋ ์ดํดํ๊ธฐ ์ด๋ ค์ธ ์ ์๋ค. ์ํ๋ ์์ ์ ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ์ผ๋ก ํํํ๋ ๊ฒ์กฐ์ฐจ ์ด๋ ค์ธ์ง ๋ชจ๋ฅธ๋ค. ์ฑ๊ณตํ์ฌ ํ๋ก๊ทธ๋จ์ด ๋์ํ๋๋ผ๋ ์ฅ์ ์ด ๋ฌด์์ธ์ง ์ฝ๊ฒ ์ ๋ฟ์ง ์์ ์๋ ์๋ค. ์คํธ๋ฆผ์ ๊ทธ์ ๋ ํ๋์ API๊ฐ ์๋, ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ๊ธฐ์ดํ ํจ๋ฌ๋ค์์ด๊ธฐ ๋๋ฌธ์ด๋ค. ์คํธ๋ฆผ์ด ์ ๊ณตํ๋ ํํ๋ ฅ, ์๋, (์ํฉ์ ๋ฐ๋ผ์๋) ๋ณ๋ ฌ์ฑ์ ์ป์ผ๋ ค๋ฉด API๋ ๋งํ ๊ฒ ๋ ์๊ณ ์ด ํจ๋ฌ๋ค์๊น์ง ํจ๊ป ๋ฐ์๋ค์ฌ์ผ ํ๋ค.
// ์คํธ๋ฆผ ํจ๋ฌ๋ค์์ ์ดํดํ์ง ๋ชปํ ์ฑ API๋ง ์ฌ์ฉํ๋ค - ๋ฐ๋ผ ํ์ง ๋ง ๊ฒ!
Map<String, Long> freq = new HashMap<>();
try (Stream<String> words = new Scanner(file).tokens()) {
words.forEach(word -> {
freq.merge(word.toLowerCase(), 1L, Long::sum);
});
}
- forEach๊ฐ ๊ทธ์ ์คํธ๋ฆผ์ด ์ํํ ์ฐ์ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ผ ์ด์์ ํ๋ ๊ฒ(์ด ์์์๋ ๋๋ค๊ฐ ์ํ๋ฅผ ์์ ํจ)์ ๋ณด๋ ๋์ ์ฝ๋์ผ ๊ฒ ๊ฐ์ ๋์๊ฐ ๋๋ค.
// ์คํธ๋ฆผ์ ์ ๋๋ก ํ์ฉํด ๋น๋ํ๋ฅผ ์ด๊ธฐํํ๋ค.
Map<String, Long> freq;
try (Stream<String> words = new Scanner(file).tokens()) {
freq = words
.collect(groupingBy(String::toLowerCase, counting()));
}
- forEach ์ฐ์ฐ์ ์ข
๋จ ์ฐ์ฐ ์ค ๊ธฐ๋ฅ์ด ๊ฐ์ฅ ์ ๊ณ ๊ฐ์ฅ โ๋โ ์คํธ๋ฆผ๋ต๋ค.
๋๋๊ณ ๋ฐ๋ณต์ ์ด๋ผ์ ๋ณ๋ ฌํํ ์๋ ์๋ค.
forEach ์ฐ์ฐ์ ์คํธ๋ฆผ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ํ ๋๋ง ์ฌ์ฉํ๊ณ , ๊ณ์ฐํ๋ ๋ฐ๋ ์ฐ์ง ๋ง์.
๋ฌผ๋ก ๊ฐ๋์ ์คํธ๋ฆผ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ์กด ์ปฌ๋ ์ ์ ์ถ๊ฐํ๋ ๋ฑ์ ๋ค๋ฅธ ์ฉ๋๋ก๋ ์ธ ์ ์๋ค.
-
์ด ์ฝ๋๋ ์์ง๊ธฐ(collector)๋ฅผ ์ฌ์ฉํ๋๋ฐ, ์คํธ๋ฆผ์ ์ฌ์ฉํ๋ ค๋ฉด ๊ผญ ๋ฐฐ์์ผ ํ๋ ์๋ก์ด ๊ฐ๋ ์ด๋ค. java.util.stream.Collectors ํด๋์ค๋ ๋ฉ์๋๋ฅผ ๋ฌด๋ ค 39๊ฐ๋ ๊ฐ์ง๊ณ ์๊ณ , ๊ทธ์ค์๋ ํ์ ๋งค๊ฐ๋ณ์๊ฐ 5๊ฐ๋ ๋๋ ๊ฒ๋ ์๋ค.
-
์ฒ์์๋ ์ฝ๊ฒ ์ถ์(reduction) ์ ๋ต์ ์บก์ํํ ๋ธ๋๋ฐ์ค ๊ฐ์ฒด๋ผ๊ณ ์๊ฐํ๊ธฐ ๋ฐ๋๋ค. ์ฌ๊ธฐ์ ์ถ์๋ ์คํธ๋ฆผ์ ์์๋ค์ ๊ฐ์ฒด ํ๋์ ์ทจํฉํ๋ค๋ ๋ป์ด๋ค. ์์ง๊ธฐ๊ฐ ์์ฑํ๋ ๊ฐ์ฒด๋ ์ผ๋ฐ์ ์ผ๋ก ์ปฌ๋ ์ ์ด๋ฉฐ, ๊ทธ๋์ โcollectorโ๋ผ๋ ์ด๋ฆ์ ์ด๋ค.
-
์์ง๊ธฐ๋ฅผ ์ฌ์ฉํ๋ฉด ์คํธ๋ฆผ์ ์์๋ฅผ ์์ฝ๊ฒ ์ปฌ๋ ์ ์ผ๋ก ๋ชจ์ ์ ์๋ค. ์์ง๊ธฐ๋ ์ด ์ธ ๊ฐ์ง๋ก, toList(), toSet(), toCollection(collectionFactory)๋ค.
List<String> topTen = freq.keySet().stream()
.sorted(comparing(freq::get).reversed())
.limit(10)
.collect(toList());
- comparing ๋ฉ์๋๋ ํค ์ถ์ถ ํจ์๋ฅผ ๋ฐ๋ ๋น๊ต์ ์์ฑ ๋ฉ์๋(์์ดํ 14)๋ค.
- ํ์ ์ ๋ฉ์๋ ์ฐธ์กฐ์ด์, ์ฌ๊ธฐ์ ํค ์ถ์ถ ํจ์๋ก ์ฐ์ธ freq::get์ ์ ๋ ฅ๋ฐ์ ๋จ์ด(ํค)๋ฅผ ๋น๋ํ์์ ์ฐพ์(์ถ์ถ) ๊ทธ ๋น๋๋ฅผ ๋ฐํํ๋ค.
- ๊ฐ์ฅ ํํ ๋จ์ด๊ฐ ์๋ก ์ค๋๋ก ๋น๊ต์(comparing)๋ฅผ ์ญ์(reversed)์ผ๋ก ์ ๋ ฌํ๋ค(sorted).
- ๋ง์ง๋ง toList๋ Collectors์ ๋ฉ์๋๋ค. ์ด์ฒ๋ผ Collectors์ ๋ฉค๋ฒ๋ฅผ ์ ์ ์ํฌํธํ์ฌ ์ฐ๋ฉด ์คํธ๋ฆผ ํ์ดํ๋ผ์ธ ๊ฐ๋ ์ฑ์ด ์ข์์ ธ, ํํ๋ค ์ด๋ ๊ฒ ์ฌ์ฉํ๋ค.
private static final Map<String, Operation> stringToEnum =
Stream.of(values()).collect(toMap(Object::toString, e -> e));
- ์ด ๊ฐ๋จํ toMap ํํ๋ ์คํธ๋ฆผ์ ๊ฐ ์์๊ฐ ๊ณ ์ ํ ํค์ ๋งคํ๋์ด ์์ ๋์ ํฉํ๋ค. ์คํธ๋ฆผ ์์ ๋ค์๊ฐ ๊ฐ์ ํค๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ํ์ดํ๋ผ์ธ์ด IllegalStateException์ ๋์ง๋ฉฐ ์ข ๋ฃ๋ ๊ฒ์ด๋ค.
- ๋ ๋ณต์กํ ํํ์ toMap์ด๋ groupingBy๋ ์ด๋ฐ ์ถฉ๋์ ๋ค๋ฃจ๋ ๋ค์ํ ์ ๋ต์ ์ ๊ณตํ๋ค.
Map<Artist, Album> topHits = albums.collect(toMap(Album::artist, a->a, maxBy(comparing(Album::sales))));
- ์ธ์ 3๊ฐ๋ฅผ ๋ฐ๋ toMap์ ์ด๋ค ํค์ ๊ทธ ํค์ ์ฐ๊ด๋ ์์๋ค ์ค ํ๋๋ฅผ ๊ณจ๋ผ์ฐ๊ด ์ง๋ ๋งต์ ๋ง๋ค ๋ ์ ์ฉํ๋ค.
- ์ฌ๊ธฐ์ ๋น๊ต์๋ก๋ BinaryOperator์์ ์ ์ ์ํฌํธํ maxBy๋ผ๋ ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ค. maxBy๋ Comparator๋ฅผ ์ ๋ ฅ๋ฐ์ BinaryOperator๋ฅผ ๋๋ ค์ค๋ค. ์ด ๊ฒฝ์ฐ ๋น๊ต์ ์์ฑ ๋ฉ์๋์ธ comparing์ด maxBy์ ๋๊ฒจ์ค ๋น๊ต์๋ฅผ ๋ฐํํ๋๋ฐ, ์์ ์ ํค ์ถ์ถ ํจ์๋ก๋ Album::sales๋ฅผ ๋ฐ์๋ค.
toMap(keyMapper, valueMapper, (oldVal, newVal) -> newVal)
- ์ธ์๊ฐ 3๊ฐ์ธ toMap์ ์ถฉ๋์ด ๋๋ฉด ๋ง์ง๋ง ๊ฐ์ ์ทจํ๋(last-write-wins) ์์ง๊ธฐ๋ฅผ ๋ง๋ค ๋๋ ์ ์ฉํ๋ค. ๋ง์ ์คํธ๋ฆผ์ ๊ฒฐ๊ณผ๊ฐ ๋น๊ฒฐ์ ์ ์ด๋ค. ํ์ง๋ง ๋งคํ ํจ์๊ฐ ํค ํ๋์ ์ฐ๊ฒฐํด์ค ๊ฐ๋ค์ด ๋ชจ๋ ๊ฐ์ ๋, ํน์ ๊ฐ์ด ๋ค๋ฅด๋๋ผ๋ ๋ชจ๋ ํ์ฉ๋๋ ๊ฐ์ผ ๋ ์ด๋ ๊ฒ ๋์ํ๋ ์์ง๊ธฐ๊ฐ ํ์ํ๋ค.
4. ์ํ๋ฒณํํ ๋จ์ด๋ฅผ ์ํ๋ฒณํ ๊ฒฐ๊ณผ๊ฐ ๊ฐ์ ๋จ์ด๋ค์ ๋ฆฌ์คํธ๋ก ๋งคํํ๋ ๋งต์ ์์ฑ
// alphabetize ๊ธฐ์ค์ผ๋ก ๊ทธ๋ฃจํ
Map<String, List<String> req = words.collect(groupingBy(word -> alphabetize(word)))
// map value์ list๋ฅผ ์ถ์
Map<String, Long> freq = words.collect(groupingBy(String::toLowerCase, counting()));
// ๋ค๋ฅธ map ๊ตฌํ์ฒด๋ฅผ ์ฌ์ฉํ๋ค.
Map<String, Long> freq = words.collect(groupingBy(String::toLowerCase, TreeMap::new, counting()));
- groupingBy๋ ๋ถ๋ฅ ํจ์(classifier)๋ฅผ ๋ฐ๊ณ ์ถ๋ ฅ์ผ๋ก๋ ์์๋ค์ ์นดํ ๊ณ ๋ฆฌ๋ณ๋ก ๋ชจ์ ๋์ ๋งต์ ๋ด์ ์์ง๊ธฐ๋ฅผ ๋ฐํํ๋ค.
-
๋ง์ด ์ฐ์ด์ง ์์ง๋ง groupingBy์ ์ฌ์ด๊ฒฉ์ธ partitioningBy๋ ์๋ค. ๋ถ๋ฅ ํจ์ ์๋ฆฌ์ ํ๋ ๋ํคํธ(predicate)๋ฅผ ๋ฐ๊ณ ํค๊ฐ Boolean์ธ ๋งต์ ๋ฐํํ๋ค.
-
Stream์ count ๋ฉ์๋๋ฅผ ์ง์ ์ฌ์ฉํ์ฌ ๊ฐ์ ๊ธฐ๋ฅ์ ์ํํ ์ ์์ผ๋ collect (counting()) ํํ๋ก ์ฌ์ฉํ ์ผ์ ์ ํ ์๋ค. Collections์๋ ์ด๋ฐ ์์ฑ์ ๋ฉ ์๋๊ฐ 16๊ฐ๋ ๋ ์๋ค. ๊ทธ์ค 9๊ฐ๋ ์ด๋ฆ์ด summing, averaging, summarizing ์ผ๋ก ์์ํ๋ฉฐ ๊ฐ๊ฐ int, long, double ์คํธ๋ฆผ์ฉ์ผ๋ก ํ๋์ฉ ์กด์ฌํ๋ค.
-
minBy์ maxBy๋ ์ธ์๋ก ๋ฐ์ ๋น๊ต์๋ฅผ ์ด์ฉํด ์คํธ๋ฆผ์์ ๊ฐ์ด ๊ฐ์ฅ ์์ ํน์ ๊ฐ์ฅ ํฐ ์์๋ฅผ ์ฐพ์ ๋ฐํํ๋ค. Stream ์ธํฐํ์ด์ค์ min๊ณผ max ๋ฉ์๋๋ฅผ ์ด์ง ์ผ๋ฐํํ ๊ฒ์ด๋ค.
-
joining์ (๋ฌธ์์ด ๋ฑ์) CharSequence ์ธ์คํด์ค์ ์คํธ๋ฆผ์๋ง ์ ์ฉํ ์ ์๋ค. ์ด ์ค ๋งค๊ฐ๋ณ์๊ฐ ์๋ joining์ ๋จ์ํ ์์๋ค์ ์ฐ๊ฒฐ(concatenate)ํ๋ ์์ง๊ธฐ๋ฅผ ๋ฐํํ๋ค.
์คํธ๋ฆผ ํ์ดํ๋ผ์ธ ํ๋ก๊ทธ๋๋ฐ์ ํต์ฌ์ ๋ถ์์ฉ ์๋ ํจ์ ๊ฐ์ฒด์ ์๋ค.
์คํธ๋ฆผ๋ฟ ์๋๋ผ ์คํธ๋ฆผ ๊ด๋ จ ๊ฐ์ฒด์ ๊ฑด๋ค์ง๋ ๋ชจ๋ ํจ์ ๊ฐ์ฒด๊ฐ ๋ถ์์ฉ์ด ์์ด์ผ ํ๋ค.
์ข ๋จ ์ฐ์ฐ ์ค forEach๋ ์คํธ๋ฆผ์ด ์ํํ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ํ ๋๋ง ์ด์ฉํด์ผ ํ๋ค.
๊ณ์ฐ ์์ฒด์๋ ์ด์ฉํ์ง ๋ง์.
์คํธ๋ฆผ์ ์ฌ๋ฐ๋ก ์ฌ์ฉํ๋ ค๋ฉด ์์ง๊ธฐ๋ฅผ ์ ์์๋ฌ์ผ ํ๋ค.
๊ฐ์ฅ ์ค์ํ ์์ง๊ธฐ ํฉํฐ๋ฆฌ๋ toList, toSet, toMap, groupingBy, joining์ด๋ค.