item 46 incheol - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki

Effective Java 3e ์•„์ดํ…œ 46๋ฅผ ์š”์•ฝํ•œ ๋‚ด์šฉ ์ž…๋‹ˆ๋‹ค.

์ŠคํŠธ๋ฆผ์€ ๊ทธ์ € ๋˜ ํ•˜๋‚˜์˜ 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;
	});
}

์ด๋Š” ์ŠคํŠธ๋ฆผ ์ฝ”๋“œ๋ฅผ ๊ฐ€์žฅํ•œ ๋ฐ˜๋ณต์  ์ฝ”๋“œ๋‹ค. ์ŠคํŠธ๋ฆผ API์˜ ์ด์ ์„ ์‚ด๋ฆฌ์ง€ ๋ชปํ•˜์˜€๋‹ค. ์ด ์ฝ”๋“œ์˜ ๋ชจ๋“  ์ž‘์—…์ด ์ข…๋‹จ ์—ฐ์‚ฐ์ธ forEach์—์„œ ์ผ์–ด๋‚˜๋Š”๋ฐ, ์ด๋•Œ ์™ธ๋ถ€ ์ƒํƒœ(๋นˆ๋„ํ‘œ)๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋žŒ๋‹ค๋ฅผ ์‹คํ–‰ํ•˜๋ฉด์„œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด๋‹ค. forEach๊ฐ€ ๊ทธ์ € ์ŠคํŠธ๋ฆผ์ด ์ˆ˜ํ–‰ํ•œ ์—ฐ์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์ผ ์ด์ƒ์„ ํ•˜๋Š” ๊ฒƒ์„๋ณด๋‹ˆ ๋‚˜์œ ์ฝ”๋“œ์ผ ๊ฒƒ ๊ฐ™์€ ๋ƒ„์ƒˆ๊ฐ€ ๋‚œ๋‹ค.

forEach ์—ฐ์‚ฐ์€ ์ข…๋‹จ ์—ฐ์‚ฐ ์ค‘ ๊ธฐ๋Šฅ์ด ๊ฐ€์žฅ ์ ๊ณ  ๊ฐ€์žฅ '๋œ' ์ŠคํŠธ๋ฆผํ•˜๋‹ค. ๋Œ€๋†“๊ณ  ๋ฐ˜๋ณต์ ์ด๋ผ์„œ ๋ณ‘๋ ฌํ™”ํ•  ์ˆ˜๋„ ์—†๋‹ค. forEach ์—ฐ์‚ฐ์€ ์ŠคํŠธ๋ฆผ ๊ณ„์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ํ•  ๋•Œ๋งŒ ์‚ฌ์šฉํ•˜๊ณ , ๊ณ„์‚ฐํ•˜๋Š” ๋ฐ๋Š” ์“ฐ์ง€ ๋ง์ž.

์œ„์˜ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐœ์„ ๋  ์ˆ˜ ์žˆ๋‹ค.

Map<String, Long> freq;
try (Stream<String> words = new Scanner(file).tokens()) {
	freq = words.
		collection(groupingBy(String::toLowerCase, counting()));
}

์ŠคํŠธ๋ฆผ์˜ ๋‹ค์–‘ํ•œ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด์ž

์ˆ˜์ง‘๊ธฐ๊ฐ€ ์ƒ์„ฑํ•˜๋Š” ๊ฐ์ฒด๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ปฌ๋ ‰์…˜์ด๋ฉฐ, ๊ทธ๋ž˜์„œ "collector"๋ผ๋Š” ์ด๋ฆ„์„ ์“ด๋‹ค.

์ˆ˜์ง‘๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ŠคํŠธ๋ฆผ์˜ ์›์†Œ๋ฅผ ์†์‰ฝ๊ฒŒ ์ปฌ๋ ‰์…˜์œผ๋กœ ๋ชจ์„ ์ˆ˜ ์žˆ๋‹ค.

๋นˆ๋„ํ‘œ์—์„œ ๊ฐ€์žฅ ํ”ํ•œ ๋‹จ์–ด 10๊ฐœ๋ฅผ ๋ฝ‘์•„๋‚ด๋Š” ํŒŒ์ดํ”„๋ผ์ธ

List<String> topTen = freq.keySet().stream()
	.sorted(comparing(freq::get).reversed())
	.limit(10)
	.collect(toList());

comparing ๋ฉ”์„œ๋“œ๋Š” ํ‚ค ์ถ”์ถœ ํ•จ์ˆ˜๋ฅผ ๋ฐ›๋Š” ๋น„๊ต์ž ์ƒ์„ฑ ๋ฉ”์„œ๋“œ๋‹ค.

์˜ˆ์ปจ๋Œ€ ๋‹ค์–‘ํ•œ ์Œ์•…๊ฐ€์˜ ์•จ๋ฒ”๋“ค์„ ๋‹ด์€ ์ŠคํŠธ๋ฆผ์„ ๊ฐ€์ง€๊ณ , ์Œ์•…๊ฐ€์™€ ๊ทธ ์Œ์•…๊ฐ€์˜ ๋ฒ ์ŠคํŠธ ์•จ๋ฒ”์„ ์—ฐ๊ด€ ์ง“๊ณ  ์‹ถ๋‹ค๊ณ  ํ•ด๋ณด์ž.

์—ด๊ฑฐ ํƒ€์ž… ์ƒ์ˆ˜์˜ ๋ฌธ์ž์—ด์„ ํ‘œํ˜„์„ ์—ด๊ฑฐ ํƒ€์ž… ์ž์ฒด์— ๋งคํ•‘

private static final Map<String, Operation> stringToEnum =
        Stream.of(values()).collect(toMap(Object::toString, e -> e));

toMap ํ˜•ํƒœ๋Š” ์ŠคํŠธ๋ฆผ์˜ ๊ฐ ์›์†Œ๊ฐ€ ๊ณ ์œ ํ•œ ํ‚ค์— ๋งคํ•‘๋˜์–ด ์žˆ์„ ๋•Œ ์ ํ•ฉํ•˜๋‹ค. ์ŠคํŠธ๋ฆผ ์›์†Œ ๋‹ค์ˆ˜๊ฐ€ ๊ฐ™์€ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ํŒŒ์ดํ”„๋ผ์ธ์ด IllegalStateException์„ ๋˜์ง€๋ฉฐ ์ข…๋ฃŒ๋  ๊ฒƒ์ด๋‹ค.

๊ฐ ํ‚ค์™€ ํ•ด๋‹น ํ‚ค์˜ ํŠน์ • ์›์†Œ๋ฅผ ์—ฐ๊ด€ ์ง“๋Š” ๋งต์„ ์ƒ์„ฑํ•˜๋Š” ์ˆ˜์ง‘๊ธฐ

Map<Artist, Album> topHits = albums.collect(
	toMap(Album::artist, a->a, maxBy(comparing(Album::sales))));

์œ„์˜ ์ฝ”๋“œ๋ฅผ ๋ง๋กœ ํ’€์–ด๋ณด์ž๋ฉด "์•จ๋ฒ” ์ŠคํŠธ๋ฆผ์„ ๋งต์œผ๋กœ ๋ฐ”๊พธ๋Š”๋ฐ, ์ด ๋งต์€ ๊ฐ ์Œ์•…๊ฐ€์™€ ๊ทธ ์Œ์•…๊ฐ€์˜ ๋ฒ ์ŠคํŠธ ์•จ๋ฒ”์„ ์ง์ง€์€ ๊ฒƒ์ด๋‹ค"๋Š” ์ด์•ผ๊ธฐ๋‹ค.

๊ทธ ์™ธ

  • groupingBy์˜ ์‚ฌ์ดŒ๊ฒฉ์ธ partitioningBy๋„ ์žˆ๋‹ค. ๋ถ„๋ฅ˜ ํ•จ์ˆ˜ ์ž๋ฆฌ์— ํ”„๋ ˆ๋””ํ‚ค๋“œ(predicate)๋ฅผ ๋ฐ›๊ณ  ํ‚ค๊ฐ€ Boolean์ธ ๋งต์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • Stream์˜ count ๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ collect(counting()) ํ˜•ํƒœ๋กœ ์‚ฌ์šฉํ•  ์ผ์€ ์ „ํ˜€ ์—†๋‹ค. Collections์—๋Š” ์ด๋Ÿฐ ์†์„ฑ์˜ ๋ฉ”์„œ๋“œ๊ฐ€ 16๊ฐœ๋‚˜ ๋” ์žˆ๋‹ค. ๊ทธ์ค‘ 9๊ฐœ๋Š” ์ด๋ฆ„์ด summing, averaging, summarizing ์œผ๋กœ ์‹œ์ž‘ํ•˜๋ฉฐ, ๊ฐ๊ฐ int, long, double ์ŠคํŠธ๋ฆผ์šฉ์œผ๋กœ ํ•˜๋‚˜์”ฉ ์กด์žฌํ•œ๋‹ค.
  • minBy, maxBy๋Š” ์ธ์ˆ˜๋กœ ๋ฐ›์€ ๋น„๊ต์ž๋ฅผ ์ด์šฉํ•ด ์ŠคํŠธ๋ฆผ์—์„œ ๊ฐ’์ด ๊ฐ€์žฅ ์ž‘์€ ํ˜น์€ ๊ฐ€์žฅ ํฐ ์›์†Œ๋ฅผ ์ฐพ์•„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • Collectors์˜ joining ๋ฉ”์„œ๋“œ๋Š” CharSequence ์ธ์Šคํ„ด์Šค์˜ ์ŠคํŠธ๋ฆผ์—๋งŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋ฉ”์†Œ๋“œ๋Š” ์—ฐ๊ฒฐ ๋ถ€์œ„์— ๊ตฌ๋ถ„๋ฌธ์ž๋ฅผ ์‚ฝ์ž…ํ•˜๋Š”๋ฐ, ์˜ˆ์ปจ๋Œ€ ๊ตฌ๋ถ„๋ฌธ์ž๋กœ ์‰ผํ‘œ(,)๋ฅผ ์ž…๋ ฅํ•˜๋ฉด CSV ํ˜•ํƒœ์˜ ๋ฌธ์ž์—ด์„ ๋งŒ๋“ค์–ด์ค€๋‹ค.

์ •๋ฆฌ

์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•ต์‹ฌ์€ ๋ถ€์ž‘์šฉ ์—†๋Š” ํ•จ์ˆ˜ ๊ฐ์ฒด์— ์žˆ๋‹ค. ์ŠคํŠธ๋ฆผ๋ฟ ์•„๋‹ˆ๋ผ ์ŠคํŠธ๋ฆผ ๊ด€๋ จ ๊ฐ์ฒด์— ๊ฑด๋„ค์ง€๋Š” ๋ชจ๋“  ํ•จ์ˆ˜ ๊ฐ์ฒด๊ฐ€ ๋ถ€์ž‘์šฉ์ด ์—†์–ด์•ผ ํ•œ๋‹ค. ์ข…๋‹จ ์—ฐ์‚ฐ ์ค‘ forEach๋Š” ์ŠคํŠธ๋ฆผ์ด ์ˆ˜ํ–‰ํ•œ ๊ณ„์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ํ•  ๋•Œ๋งŒ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค. ๊ณ„์‚ฐ ์ž์ฒด์—๋Š” ์ด์šฉํ•˜์ง€ ๋ง์ž. ์ŠคํŠธ๋ฆผ์„ ์˜ฌ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ˆ˜์ง‘๊ธฐ๋ฅผ ์ž˜ ์•Œ์•„๋‘ฌ์•ผ ํ•œ๋‹ค. ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ˆ˜์ง‘๊ธฐ ํŒฉํ„ฐ๋ฆฌ๋Š” toList, toSet, toMap, groupingBy, joining์ด๋‹ค.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ