๐Ÿˆ Guava: ๊ตฌ๊ธ€์˜ ํ•ต์‹ฌ ์ž๋ฐ” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๐Ÿˆ

์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿˆ Guava: ๊ตฌ๊ธ€์˜ ํ•ต์‹ฌ ์ž๋ฐ” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๐Ÿˆ

 

 

์•ˆ๋…•, ์ž๋ฐ” ๊ฐœ๋ฐœ์ž ์นœ๊ตฌ๋“ค! ์˜ค๋Š˜์€ ์ •๋ง ์žฌ๋ฏธ์žˆ๊ณ  ์œ ์šฉํ•œ ์ฃผ์ œ๋ฅผ ๊ฐ€์ง€๊ณ  ์™”์–ด. ๋ฐ”๋กœ ๊ตฌ๊ธ€์—์„œ ๋งŒ๋“  Guava ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์•ผ. ์ด ๋…€์„, ์ •๋ง ๋Œ€๋‹จํ•˜๋‹ค๊ณ ! ์ž๋ฐ” ๊ฐœ๋ฐœํ•  ๋•Œ ์—†์–ด์„œ๋Š” ์•ˆ ๋  ์นœ๊ตฌ ๊ฐ™์€ ์กด์žฌ๋ผ๋‹ˆ๊นŒ. ๐Ÿ˜Ž

์šฐ๋ฆฌ๊ฐ€ ์ด Guava์— ๋Œ€ํ•ด ๊นŠ์ด ํŒŒ๊ณ ๋“ค๋ฉด์„œ, ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ƒˆ๋กœ์šด ์žฌ๋Šฅ์„ ๋ฐœ๊ฒฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์‹ ์„ ํ•œ ๊ฒฝํ—˜์„ ํ•  ๊ฑฐ์•ผ. ์ž, ๊ทธ๋Ÿผ ์ด ๋ฉ‹์ง„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์„ธ๊ณ„๋กœ ํ•จ๊ป˜ ๋– ๋‚˜๋ณผ๊นŒ?

๐Ÿš€ Guava๋ž€?

Guava๋Š” ๊ตฌ๊ธ€์—์„œ ๊ฐœ๋ฐœํ•œ ์˜คํ”ˆ์†Œ์Šค ์ž๋ฐ” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์•ผ. ์ด ๋…€์„์€ ์ž๋ฐ” ๊ฐœ๋ฐœ์ž๋“ค์˜ ์ƒ์‚ฐ์„ฑ์„ ์—„์ฒญ๋‚˜๊ฒŒ ๋†’์—ฌ์ฃผ๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค๋“ค์˜ ๋ชจ์Œ์ด์ง€. ์ปฌ๋ ‰์…˜, ์บ์‹ฑ, ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ, I/O ๋“ฑ ๋‹ค์–‘ํ•œ ์˜์—ญ์—์„œ ์šฐ๋ฆฌ์˜ ์ฝ”๋”ฉ ์ƒํ™œ์„ ๋”์šฑ ํŽธ๋ฆฌํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ค˜.

๐ŸŒŸ Guava์˜ ์ฃผ์š” ํŠน์ง•

  • โœ… ํ’๋ถ€ํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค
  • โœ… ์„ฑ๋Šฅ ์ตœ์ ํ™”
  • โœ… ์•ˆ์ •์„ฑ๊ณผ ์‹ ๋ขฐ์„ฑ
  • โœ… ์ง€์†์ ์ธ ์—…๋ฐ์ดํŠธ์™€ ์ปค๋ฎค๋‹ˆํ‹ฐ ์ง€์›
  • โœ… ์‰ฌ์šด ์‚ฌ์šฉ๋ฒ•

์ด์ œ๋ถ€ํ„ฐ Guava์˜ ์ฃผ์š” ๊ธฐ๋Šฅ๋“ค์„ ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ณผ ๊ฑฐ์•ผ. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ์„ ๊ตฌ๊ฒฝํ•˜๋“ฏ์ด, Guava์˜ ๋‹ค์ฑ„๋กœ์šด ๊ธฐ๋Šฅ๋“ค์„ ํƒํ—˜ํ•ด๋ณด์ž๊ณ !

๐Ÿงฉ Guava์˜ ์ปฌ๋ ‰์…˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ

์ž, ์ด์ œ Guava์˜ ์ฒซ ๋ฒˆ์งธ ๋งค๋ ฅ ํฌ์ธํŠธ, ์ปฌ๋ ‰์…˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฑฐ์•ผ. ์ด ๋…€์„๋“ค์€ ์ •๋ง ๋Œ€๋‹จํ•ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์žฌ๋‹ค๋Šฅํ•œ ํ”„๋ฆฌ๋žœ์„œ๋ฅผ ๋งŒ๋‚œ ๊ฒƒ ๊ฐ™์€ ๋Š๋‚Œ์ด๋ž„๊นŒ? ๐Ÿ˜‰

1. Immutable ์ปฌ๋ ‰์…˜

Guava๋Š” ๋ถˆ๋ณ€(Immutable) ์ปฌ๋ ‰์…˜์„ ์ œ๊ณตํ•ด. ์ด๊ฒŒ ๋ญ๊ฐ€ ์ข‹๋ƒ๊ณ ? ์Œ, ์ƒ์ƒํ•ด๋ด. ๋„ค๊ฐ€ ๋งŒ๋“  ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๋ชฐ๋ž˜ ๋ฐ”๊ฟ”๋ฒ„๋ฆฌ๋ฉด ์–ด๋–จ๊นŒ? ์•„์ฐ”ํ•˜์ง€? ๊ทธ๋ž˜์„œ ๋ถˆ๋ณ€ ์ปฌ๋ ‰์…˜์ด ํ•„์š”ํ•œ ๊ฑฐ์•ผ.

๐Ÿ”’ Immutable ์ปฌ๋ ‰์…˜์˜ ์žฅ์ :

  • ์Šค๋ ˆ๋“œ ์•ˆ์ „์„ฑ ๋ณด์žฅ
  • ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์ˆ˜์ • ๋ฐฉ์ง€
  • ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์„ฑ

์ž, ์ด์ œ ์ฝ”๋“œ๋กœ ํ•œ๋ฒˆ ๋ณผ๊นŒ?


import com.google.common.collect.ImmutableList;

ImmutableList<String> fruits = ImmutableList.of("์‚ฌ๊ณผ", "๋ฐ”๋‚˜๋‚˜", "์ฒด๋ฆฌ");
// fruits.add("๋”ธ๊ธฐ");  // ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ด. ๋ถˆ๋ณ€์ด๋‹ˆ๊นŒ!

์™€! ์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ถˆ๋ณ€ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด. ์ด์ œ ๋ˆ„๊ฐ€ ๋ชฐ๋ž˜ ๊ณผ์ผ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋นผ๋ ค๊ณ  ํ•ด๋„ ์•ˆ ๋ผ. ์šฐ๋ฆฌ์˜ ๊ณผ์ผ ๋ฐ”๊ตฌ๋‹ˆ๋Š” ์•ˆ์ „ํ•ด! ๐ŸŽ๐ŸŒ๐Ÿ’

2. Multiset

๋‹ค์Œ์€ Multiset์ด์•ผ. ์ด ๋…€์„์€ ์ •๋ง ์žฌ๋ฐŒ์–ด. ์ผ๋ฐ˜ Set์ด๋ž‘ ๋น„์Šทํ•œ๋ฐ, ์ค‘๋ณต ์š”์†Œ๋ฅผ ํ—ˆ์šฉํ•ด. ๊ทธ๋ฆฌ๊ณ  ๊ฐ ์š”์†Œ์˜ ๊ฐœ์ˆ˜๋„ ์„ธ์–ด์ค˜. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ธ๊ธฐ ์žˆ๋Š” ์žฌ๋Šฅ์„ ์ง‘๊ณ„ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์•ผ!

Multiset ๊ฐœ๋… ๋„์‹ํ™” Multiset A B C A B A count: 3 count: 2 count: 1

์ž, ์ด์ œ ์ฝ”๋“œ๋กœ ํ•œ๋ฒˆ ์จ๋ณผ๊นŒ?


import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;

Multiset<String> bookBag = HashMultiset.create();
bookBag.add("ํ•ด๋ฆฌ ํฌํ„ฐ");
bookBag.add("ํ•ด๋ฆฌ ํฌํ„ฐ");
bookBag.add("๋ฐ˜์ง€์˜ ์ œ์™•");

System.out.println(bookBag.count("ํ•ด๋ฆฌ ํฌํ„ฐ")); // ์ถœ๋ ฅ: 2
System.out.println(bookBag.count("๋ฐ˜์ง€์˜ ์ œ์™•")); // ์ถœ๋ ฅ: 1

์™€์šฐ! ์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ฐ ์ฑ…์˜ ๊ฐœ์ˆ˜๋ฅผ ์…€ ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ๋„์„œ๊ด€ ์‚ฌ์„œ๊ฐ€ ๋œ ๊ฒƒ ๊ฐ™์ง€ ์•Š์•„? ๐Ÿ“š

3. Multimap

Multimap์€ ๋˜ ๋‹ค๋ฅธ ์žฌ๋ฏธ์žˆ๋Š” ๋…€์„์ด์•ผ. ์ผ๋ฐ˜ Map์ด๋ž‘ ๋น„์Šทํ•œ๋ฐ, ํ•˜๋‚˜์˜ ํ‚ค์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๊ฐ’์„ ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ์–ด. ์ด๊ฑด ์ •๋ง ์œ ์šฉํ•ด. ์˜ˆ๋ฅผ ๋“ค์–ด, ํ•™์ƒ๋“ค์˜ ์ทจ๋ฏธ๋ฅผ ์ •๋ฆฌํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ด.

๐ŸŽญ Multimap ์‚ฌ์šฉ ์˜ˆ์‹œ:

  • ํ•™์ƒ - ์ทจ๋ฏธ
  • ๋„์‹œ - ๋žœ๋“œ๋งˆํฌ
  • ์ž‘๊ฐ€ - ์ž‘ํ’ˆ

์ž, ์ด์ œ ์ฝ”๋“œ๋กœ ํ•œ๋ฒˆ ๋ณผ๊นŒ?


import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

Multimap<String, String> studentHobbies = ArrayListMultimap.create();
studentHobbies.put("์ฒ ์ˆ˜", "์ถ•๊ตฌ");
studentHobbies.put("์ฒ ์ˆ˜", "๊ฒŒ์ž„");
studentHobbies.put("์˜ํฌ", "๋…์„œ");
studentHobbies.put("์˜ํฌ", "๊ทธ๋ฆผ");

System.out.println(studentHobbies.get("์ฒ ์ˆ˜")); // ์ถœ๋ ฅ: [์ถ•๊ตฌ, ๊ฒŒ์ž„]
System.out.println(studentHobbies.get("์˜ํฌ")); // ์ถœ๋ ฅ: [๋…์„œ, ๊ทธ๋ฆผ]

์™€! ์ด๋ ‡๊ฒŒ ์‰ฝ๊ฒŒ ํ•œ ํ•™์ƒ์˜ ์—ฌ๋Ÿฌ ์ทจ๋ฏธ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ํ•œ ์‚ฌ๋žŒ์˜ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ์„ ์†Œ๊ฐœํ•˜๋Š” ๊ฒƒ ๊ฐ™์ง€ ์•Š์•„? ๐Ÿ˜Š

4. BiMap

BiMap์€ ์–‘๋ฐฉํ–ฅ ๋งต์ด์•ผ. ์ผ๋ฐ˜ Map์€ ํ‚ค๋กœ ๊ฐ’์„ ์ฐพ์„ ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ฐ’์œผ๋กœ ํ‚ค๋ฅผ ์ฐพ๊ธฐ๋Š” ์–ด๋ ต์ž–์•„. ํ•˜์ง€๋งŒ BiMap์€ ์–‘์ชฝ ๋‹ค ๊ฐ€๋Šฅํ•ด!

BiMap ๊ฐœ๋… ๋„์‹ํ™” BiMap Key Value

์ž, ์ด์ œ ์ฝ”๋“œ๋กœ ํ•œ๋ฒˆ ์จ๋ณผ๊นŒ?


import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;

BiMap<String, Integer> nameToId = HashBiMap.create();
nameToId.put("Alice", 1);
nameToId.put("Bob", 2);

System.out.println(nameToId.get("Alice")); // ์ถœ๋ ฅ: 1
System.out.println(nameToId.inverse().get(2)); // ์ถœ๋ ฅ: Bob

์™€์šฐ! ์ด๋ ‡๊ฒŒ ์‰ฝ๊ฒŒ ์ด๋ฆ„์œผ๋กœ ID๋ฅผ ์ฐพ๊ณ , ID๋กœ ์ด๋ฆ„์„ ์ฐพ์„ ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์žฌ๋Šฅ ์ด๋ฆ„์œผ๋กœ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ฐพ๊ณ , ์นดํ…Œ๊ณ ๋ฆฌ๋กœ ์žฌ๋Šฅ์„ ์ฐพ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ํŽธ๋ฆฌํ•˜์ง€? ๐Ÿ‘

5. Table

๋งˆ์ง€๋ง‰์œผ๋กœ ์†Œ๊ฐœํ•  ์ปฌ๋ ‰์…˜์€ Table์ด์•ผ. ์ด ๋…€์„์€ ์ •๋ง ํŠน๋ณ„ํ•ด. 2์ฐจ์› ํ…Œ์ด๋ธ” ๊ตฌ์กฐ๋ฅผ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ . ํ–‰๊ณผ ์—ด, ๊ทธ๋ฆฌ๊ณ  ๊ฐ’์œผ๋กœ ๊ตฌ์„ฑ๋ผ ์žˆ์–ด.

๐Ÿ“Š Table ์‚ฌ์šฉ ์˜ˆ์‹œ:

  • ์—‘์…€ ์‹œํŠธ ๋ฐ์ดํ„ฐ
  • ์ขŒํ‘œ ์‹œ์Šคํ…œ
  • ๋‹ค์ฐจ์› ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ

์ž, ์ด์ œ ์ฝ”๋“œ๋กœ ํ•œ๋ฒˆ ๋ณผ๊นŒ?


import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;

Table<String, String, Integer> gradeTable = HashBasedTable.create();
gradeTable.put("์ฒ ์ˆ˜", "์ˆ˜ํ•™", 90);
gradeTable.put("์ฒ ์ˆ˜", "์˜์–ด", 85);
gradeTable.put("์˜ํฌ", "์ˆ˜ํ•™", 95);
gradeTable.put("์˜ํฌ", "์˜์–ด", 92);

System.out.println(gradeTable.get("์ฒ ์ˆ˜", "์ˆ˜ํ•™")); // ์ถœ๋ ฅ: 90
System.out.println(gradeTable.column("์˜์–ด")); // ์ถœ๋ ฅ: {์ฒ ์ˆ˜=85, ์˜ํฌ=92}
System.out.println(gradeTable.row("์˜ํฌ")); // ์ถœ๋ ฅ: {์ˆ˜ํ•™=95, ์˜์–ด=92}

์™€! ์ด๋ ‡๊ฒŒ ์‰ฝ๊ฒŒ ํ•™์ƒ๋“ค์˜ ๊ณผ๋ชฉ๋ณ„ ์„ฑ์ ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๊ฐ ์‚ฌ์šฉ์ž์˜ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ๊ณผ ๊ทธ์— ๋Œ€ํ•œ ํ‰๊ฐ€๋ฅผ ํ•œ๋ˆˆ์— ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์ง€ ์•Š์•„? ๐Ÿ˜Ž

์ž, ์ด๋ ‡๊ฒŒ Guava์˜ ์ปฌ๋ ‰์…˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋“ค์„ ์‚ดํŽด๋ดค์–ด. ์ด ๋…€์„๋“ค, ์ •๋ง ๋Œ€๋‹จํ•˜์ง€? ์šฐ๋ฆฌ์˜ ์ฝ”๋”ฉ ์ƒํ™œ์„ ํ›จ์”ฌ ๋” ํŽธ๋ฆฌํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๋“ ๋“ ํ•œ ์นœ๊ตฌ๋“ค์ด์•ผ. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ์„ ๊ฐ€์ง„ ํ”„๋ฆฌ๋žœ์„œ๋“ค์„ ๋งŒ๋‚˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, Guava์˜ ์ปฌ๋ ‰์…˜๋“ค๋„ ๊ฐ์ž์˜ ํŠน๋ณ„ํ•œ ์žฌ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด. ์ด์ œ ์ด ๋…€์„๋“ค์„ ์ž˜ ํ™œ์šฉํ•ด์„œ ๋” ๋ฉ‹์ง„ ์ž๋ฐ” ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ๋˜์–ด๋ณด์ž๊ณ ! ๐Ÿ’ช

๐Ÿง  Guava์˜ ์บ์‹ฑ ๊ธฐ๋Šฅ

์ž, ์ด์ œ Guava์˜ ๋˜ ๋‹ค๋ฅธ ๋ฉ‹์ง„ ๊ธฐ๋Šฅ์ธ ์บ์‹ฑ์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฑฐ์•ผ. ์บ์‹ฑ์ด ๋ญ๋ƒ๊ณ ? ์Œ... ์ƒ์ƒํ•ด๋ด. ๋„ค๊ฐ€ ๋งค์ผ ์•„์นจ ๋˜‘๊ฐ™์€ ๊ธธ๋กœ ํ•™๊ต์— ๊ฐ€. ๊ทธ๋Ÿฐ๋ฐ ๋งค์ผ ์ง€๋„๋ฅผ ๋ณด๋ฉด์„œ ๊ฐ€? ์•„๋‹ˆ์ง€! ํ•œ ๋ฒˆ ์™ธ์šฐ๋ฉด ๊ทธ ๋‹ค์Œ๋ถ€ํ„ฐ๋Š” ๊ทธ๋ƒฅ ๊ธฐ์–ตํ•ด์„œ ๊ฐ€์ž–์•„. ๊ทธ๊ฒŒ ๋ฐ”๋กœ ์บ์‹ฑ์ด์•ผ! ๐Ÿ˜„

๐Ÿš€ ์บ์‹ฑ์˜ ์žฅ์ :

  • ๋น ๋ฅธ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ
  • ์„œ๋ฒ„ ๋ถ€ํ•˜ ๊ฐ์†Œ
  • ๋ฐ˜๋ณต์ ์ธ ๊ณ„์‚ฐ ๋ฐฉ์ง€

Guava์˜ ์บ์‹ฑ ๊ธฐ๋Šฅ์€ ์ •๋ง ๋Œ€๋‹จํ•ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ธ๊ธฐ ์žˆ๋Š” ์žฌ๋Šฅ์„ ๋ฏธ๋ฆฌ ์ค€๋น„ํ•ด๋‘๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋น ๋ฅด๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜.

1. LoadingCache

LoadingCache๋Š” Guava์˜ ์บ์‹ฑ ๊ธฐ๋Šฅ ์ค‘ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ๋…€์„์ด์•ผ. ์ด ๋…€์„์€ ์บ์‹œ์— ์—†๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋™์œผ๋กœ ๋กœ๋“œํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ด ์žˆ์–ด. ์ •๋ง ํŽธ๋ฆฌํ•˜์ง€?

LoadingCache ์ž‘๋™ ์›๋ฆฌ LoadingCache Cache Data Source A B C D Auto Load

์ž, ์ด์ œ ์ฝ”๋“œ๋กœ ํ•œ๋ฒˆ ๋ณผ๊นŒ?


import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
    .maximumSize(1000)
    .build(
        new CacheLoader<String, Integer>() {
            public Integer load(String key) {
                return heavyComputation(key);
            }
        });

// ์‚ฌ์šฉ ์˜ˆ
try {
    int result = cache.get("someKey");
    System.out.println("Result: " + result);
} catch (ExecutionException e) {
    // ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
}

// heavyComputation ๋ฉ”์„œ๋“œ๋Š” ์‹ค์ œ๋กœ ๋ฌด๊ฑฐ์šด ๊ณ„์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ผ๊ณ  ๊ฐ€์ •
private static int heavyComputation(String key) {
    // ์‹ค์ œ๋กœ๋Š” ๋ณต์žกํ•œ ๊ณ„์‚ฐ์ด ์—ฌ๊ธฐ์— ๋“ค์–ด๊ฐˆ ๊ฑฐ์•ผ
    return key.length() * 10;
}

์™€! ์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ์บ์‹œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด. ์ด์ œ "someKey"์— ๋Œ€ํ•œ ๊ณ„์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ํ•œ ๋ฒˆ๋งŒ ์ˆ˜ํ–‰ํ•˜๊ณ , ๊ทธ ๋‹ค์Œ๋ถ€ํ„ฐ๋Š” ์บ์‹œ์—์„œ ๋ฐ”๋กœ ๊ฐ€์ ธ์˜ค์ง€. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ธ๊ธฐ ์žˆ๋Š” ์žฌ๋Šฅ์„ ๋ฏธ๋ฆฌ ์ค€๋น„ํ•ด๋‘๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์•ผ! ๐Ÿ‘

2. ์บ์‹œ ์„ค์ •

Guava์˜ ์บ์‹œ๋Š” ์ •๋ง ๋‹ค์–‘ํ•œ ์„ค์ •์ด ๊ฐ€๋Šฅํ•ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ์˜ต์…˜์œผ๋กœ ์žฌ๋Šฅ์„ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์•ผ. ๋ช‡ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ์„ค์ •์„ ์‚ดํŽด๋ณผ๊นŒ?

โš™๏ธ ์ฃผ์š” ์บ์‹œ ์„ค์ •:

  • maximumSize: ์บ์‹œ์˜ ์ตœ๋Œ€ ํฌ๊ธฐ
  • expireAfterWrite: ํ•ญ๋ชฉ์ด ์ž‘์„ฑ๋œ ํ›„ ํŠน์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ๋งŒ๋ฃŒ
  • expireAfterAccess: ํ•ญ๋ชฉ์— ๋งˆ์ง€๋ง‰์œผ๋กœ ์ ‘๊ทผํ•œ ํ›„ ํŠน์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ๋งŒ๋ฃŒ
  • refreshAfterWrite: ํ•ญ๋ชฉ์ด ์ž‘์„ฑ๋œ ํ›„ ํŠน์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ์ƒˆ๋กœ๊ณ ์นจ

์ด ์„ค์ •๋“ค์„ ์‚ฌ์šฉํ•ด์„œ ์บ์‹œ๋ฅผ ๋”์šฑ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์–ด. ์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ?


LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
    .maximumSize(1000)  // ์ตœ๋Œ€ 1000๊ฐœ์˜ ํ•ญ๋ชฉ๋งŒ ์ €์žฅ
    .expireAfterWrite(10, TimeUnit.MINUTES)  // ์ž‘์„ฑ ํ›„ 10๋ถ„ ๋’ค ๋งŒ๋ฃŒ
    .refreshAfterWrite(1, TimeUnit.MINUTES)  // ์ž‘์„ฑ ํ›„ 1๋ถ„ ๋’ค ์ƒˆ๋กœ๊ณ ์นจ
    .build(
        new CacheLoader<String, Integer>() {
            public Integer load(String key) {
                return heavyComputation(key);
            }
        });

์™€์šฐ! ์ด๋ ‡๊ฒŒ ์„ค์ •ํ•˜๋ฉด ์บ์‹œ๊ฐ€ ํ•ญ์ƒ ์ตœ์‹  ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ๋„ ๋„ˆ๋ฌด ์ปค์ง€์ง€ ์•Š๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ธ๊ธฐ ์žˆ๋Š” ์žฌ๋Šฅ๋“ค์„ ์ฃผ๊ธฐ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์•ผ! ๐Ÿ˜Ž

3. ์บ์‹œ ํ†ต๊ณ„

Guava ์บ์‹œ์˜ ๋˜ ๋‹ค๋ฅธ ๋ฉ‹์ง„ ๊ธฐ๋Šฅ์€ ๋ฐ”๋กœ ํ†ต๊ณ„ ๊ธฐ๋Šฅ์ด์•ผ. ์บ์‹œ๊ฐ€ ์–ผ๋งˆ๋‚˜ ํšจ์œจ์ ์œผ๋กœ ๋™์ž‘ํ•˜๊ณ  ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์ง€. ์ด๊ฑด ์ •๋ง ์œ ์šฉํ•ด!


LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
    .maximumSize(1000)
    .recordStats()  // ํ†ต๊ณ„ ๊ธฐ๋ก ํ™œ์„ฑํ™”
    .build(
        new CacheLoader<String, Integer>() {
            public Integer load(String key) {
                return heavyComputation(key);
            }
        });

// ์บ์‹œ ์‚ฌ์šฉ ํ›„...

System.out.println(cache.stats().hitRate());  // ์บ์‹œ ํžˆํŠธ์œจ
System.out.println(cache.stats().averageLoadPenalty());  // ํ‰๊ท  ๋กœ๋”ฉ ์‹œ๊ฐ„

์ด๋ ‡๊ฒŒ ์บ์‹œ์˜ ์„ฑ๋Šฅ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๊ฐ ์žฌ๋Šฅ์˜ ์ธ๊ธฐ๋„๋ฅผ ์ฒดํฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์•ผ! ๐Ÿ‘€

4. ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ์˜ ์บ์‹ฑ

Guava์˜ ์บ์‹œ๋Š” ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ๋„ ์•ˆ์ „ํ•˜๊ฒŒ ๋™์ž‘ํ•ด. ์ด๊ฑด ์ •๋ง ์ค‘์š”ํ•œ ํŠน์ง•์ด์•ผ. ์—ฌ๋Ÿฌ ์‚ฌ๋žŒ์ด ๋™์‹œ์— ์žฌ๋Šฅ๋„ท์„ ์‚ฌ์šฉํ•ด๋„ ๋ฌธ์ œ๊ฐ€ ์—†๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๋ฌธ์ œ๊ฐ€ ์—†์–ด!


LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
    .maximumSize(1000)
    .concurrencyLevel(10)  // ๋™์‹œ์— ์ตœ๋Œ€ 10๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์บ์‹œ์— ์ ‘๊ทผ ๊ฐ€๋Šฅ
    .build(
        new CacheLoader<String, Integer>() {
            public Integer load(String key) {
                return heavyComputation(key);
            }
        });

์ด๋ ‡๊ฒŒ ์„ค์ •ํ•˜๋ฉด ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•ด๋„ ์•ˆ์ „ํ•ด. ์ •๋ง ๋Œ€๋‹จํ•˜์ง€? ๐Ÿ˜ƒ

5. ์บ์‹œ ์ œ๊ฑฐ ๋ฆฌ์Šค๋„ˆ

๋งˆ์ง€๋ง‰์œผ๋กœ ์†Œ๊ฐœํ•  ๊ธฐ๋Šฅ์€ ์บ์‹œ ์ œ๊ฑฐ ๋ฆฌ์Šค๋„ˆ์•ผ. ์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ์บ์‹œ์—์„œ ํ•ญ๋ชฉ์ด ์ œ๊ฑฐ๋  ๋•Œ ํŠน์ • ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์–ด.


LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
    .maximumSize(1000)
    .removalListener(new RemovalListener<String, Integer>() {
        public void onRemoval(RemovalNotification<String, Integer> removal) {
            System.out.println("Removed: " + removal.getKey() + " -> " + removal.getValue());
        }
    })
    .build(
        new CacheLoader<String, Integer>() {
            public Integer load(String key) {
                return heavyComputation(key);
            }
        });

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์บ์‹œ์—์„œ ํ•ญ๋ชฉ์ด ์ œ๊ฑฐ๋  ๋•Œ๋งˆ๋‹ค ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธธ ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ธ๊ธฐ ์—†๋Š” ์žฌ๋Šฅ์ด ๋ชฉ๋ก์—์„œ ์ œ๊ฑฐ๋  ๋•Œ ์•Œ๋ฆผ์„ ๋ฐ›๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์•ผ! ๐Ÿ“ข

์ž, ์ด๋ ‡๊ฒŒ Guava์˜ ์บ์‹ฑ ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด ์•Œ์•„๋ดค์–ด. ์ด ๊ธฐ๋Šฅ๋“ค์„ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ํ”„๋กœ๊ทธ๋žจ์˜ ์„ฑ๋Šฅ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ธ๊ธฐ ์žˆ๋Š” ์žฌ๋Šฅ๋“ค์„ ๋ฏธ๋ฆฌ ์ค€๋น„ํ•ด๋‘๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋น ๋ฅด๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฑฐ์ง€. ์ด์ œ ์ด ๋…€์„๋“ค์„ ํ™œ์šฉํ•ด์„œ ๋” ๋น ๋ฅด๊ณ  ํšจ์œจ์ ์ธ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค์–ด๋ณด์ž๊ณ ! ๐Ÿ’ช

๐Ÿ”„ Guava์˜ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ๊ธฐ๋Šฅ

์ž, ์ด์ œ Guava์˜ ๋˜ ๋‹ค๋ฅธ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ธ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฑฐ์•ผ. ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๊ฐ€ ๋ญ๋ƒ๊ณ ? ์Œ... ์ƒ์ƒํ•ด๋ด. ๋„ค๊ฐ€ ํ˜ผ์ž์„œ ๋ฐฉ ์ฒญ์†Œ๋ฅผ ํ•˜๋ฉด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ์ง€๋งŒ, ์นœ๊ตฌ๋“ค์ด๋ž‘ ๊ฐ™์ด ํ•˜๋ฉด ํ›จ์”ฌ ๋นจ๋ฆฌ ๋๋‚˜์ž–์•„? ๊ทธ๊ฒŒ ๋ฐ”๋กœ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ์•ผ! ๐Ÿ˜„

๐Ÿš€ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ์˜ ์žฅ์ :

  • ์ž‘์—… ์ฒ˜๋ฆฌ ์†๋„ ํ–ฅ์ƒ
  • ์‹œ์Šคํ…œ ์ž์›์˜ ํšจ์œจ์  ์‚ฌ์šฉ
  • ๋ณต์žกํ•œ ์ž‘์—…์˜ ๊ฐ„ํŽธํ•œ ์ฒ˜๋ฆฌ

Guava์˜ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ๊ธฐ๋Šฅ์€ ์ •๋ง ๋Œ€๋‹จํ•ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์—ฌ๋Ÿฌ ํ”„๋ฆฌ๋žœ์„œ๊ฐ€ ๋™์‹œ์— ์ผ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ์—ฌ๋Ÿฌ ์ž‘์—…์„ ๋™์‹œ์— ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜.

1. ListenableFuture

ListenableFuture๋Š” Guava์—์„œ ์ œ๊ณตํ•˜๋Š” Future์˜ ํ™•์žฅ ๋ฒ„์ „์ด์•ผ. ์ด ๋…€์„์€ ๋น„๋™๊ธฐ ์ž‘์—…์ด ์™„๋ฃŒ๋˜์—ˆ์„ ๋•Œ ์ฝœ๋ฐฑ์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜. ์ •๋ง ํŽธ๋ฆฌํ•˜์ง€?

ListenableFuture ์ž‘๋™ ์›๋ฆฌ ListenableFuture Async Task Callback Task Complete

์ž, ์ด์ œ ์ฝ”๋“œ๋กœ ํ•œ๋ฒˆ ๋ณผ๊นŒ?


import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));

ListenableFuture<Integer> future = service.submit(new Callable<Integer>() {
    public Integer call() {
        return heavyComputation();
    }
});

Futures.addCallback(future, new FutureCallback<Integer>() {
    public void onSuccess(Integer result) {
        System.out.println("Computation finished: " + result);
    }
    public void onFailure(Throwable thrown) {
        System.err.println("Computation failed: " + thrown);
    }
});

// heavyComputation ๋ฉ”์„œ๋“œ๋Š” ์‹ค์ œ๋กœ ๋ฌด๊ฑฐ์šด ๊ณ„์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ผ๊ณ  ๊ฐ€์ •
private static int heavyComputation() {
    // ์‹ค์ œ๋กœ๋Š” ๋ณต์žกํ•œ ๊ณ„์‚ฐ์ด ์—ฌ๊ธฐ์— ๋“ค์–ด๊ฐˆ ๊ฑฐ์•ผ
    return 42;
}

์™€! ์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„๋ณผ ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ํ”„๋ฆฌ๋žœ์„œ์—๊ฒŒ ์ž‘์—…์„ ์˜๋ขฐํ•˜๊ณ  ์™„๋ฃŒ๋˜๋ฉด ์•Œ๋ฆผ์„ ๋ฐ›๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์•ผ! ๐Ÿ‘

2. Futures ์œ ํ‹ธ๋ฆฌํ‹ฐ

Guava๋Š” Futures๋ผ๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•ด. ์ด ๋…€์„์€ Future ๊ฐ์ฒด๋“ค์„ ๋‹ค๋ฃจ๋Š” ๋ฐ ์ •๋ง ์œ ์šฉํ•œ ๋ฉ”์„œ๋“œ๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด.

๐Ÿ› ๏ธ Futures ์œ ํ‹ธ๋ฆฌํ‹ฐ์˜ ์ฃผ์š” ๊ธฐ๋Šฅ:

  • ์—ฌ๋Ÿฌ Future์˜ ๊ฒฐ๊ณผ๋ฅผ ํ•˜๋‚˜๋กœ ํ•ฉ์น˜๊ธฐ
  • Future์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ณ€ํ™˜ํ•˜๊ธฐ
  • Future์— ํƒ€์ž„์•„์›ƒ ์„ค์ •ํ•˜๊ธฐ

์ด ๊ธฐ๋Šฅ๋“ค์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ณต์žกํ•œ ๋น„๋™๊ธฐ ์ž‘์—…์„ ๋” ์‰ฝ๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์–ด. ์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ?


ListenableFuture<Integer> future1 = service.submit(new Callable<Integer>() {
    public Integer call() { return 1; }
});
ListenableFuture<Integer> future2 = service.submit(new Callable<Integer>() {
    public Integer call() { return 2; }
});

ListenableFuture<List<Integer>> combinedFutures = Futures.allAsList(future1, future2);

Futures.addCallback(combinedFutures, new FutureCallback<List<Integer>>() {
    public void onSuccess(List<Integer> result) {
        System.out.println("Combined result: " + result);
    }
    public void onFailure(Throwable thrown) {
        System.err.println("Computation failed: " + thrown);
    }
});

์™€์šฐ! ์ด๋ ‡๊ฒŒ ์—ฌ๋Ÿฌ Future์˜ ๊ฒฐ๊ณผ๋ฅผ ํ•œ ๋ฒˆ์— ๋ฐ›์•„๋ณผ ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์—ฌ๋Ÿฌ ํ”„๋ฆฌ๋žœ์„œ์˜ ์ž‘์—… ๊ฒฐ๊ณผ๋ฅผ ํ•œ ๋ฒˆ์— ํ™•์ธํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ํŽธ๋ฆฌํ•˜์ง€? ๐Ÿ˜Ž

3. RateLimiter

RateLimiter๋Š” Guava์—์„œ ์ œ๊ณตํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์ด์•ผ. ์ด ๋…€์„์€ ์ž‘์—…์˜ ์‹คํ–‰ ์†๋„๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜. ํŠน์ • ์‹œ๊ฐ„ ๋™์•ˆ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—…์˜ ์ˆ˜๋ฅผ ์ œํ•œํ•˜๋Š” ๊ฑฐ์ง€.

RateLimiter ์ž‘๋™ ์›๋ฆฌ RateLimiter Tasks Rate Limiter Execution

์ž, ์ด์ œ ์ฝ”๋“œ๋กœ ํ•œ๋ฒˆ ๋ณผ๊นŒ?


import com.google.common.util.concurrent.RateLimiter;

RateLimiter limiter = RateLimiter.create(2.0); // ์ดˆ๋‹น 2๊ฐœ์˜ ์ž‘์—…๋งŒ ํ—ˆ์šฉ

for (int i = 0; i < 10; i++) {
    limiter.acquire(); // ์ž‘์—… ์‹คํ–‰ ์ „ ๊ถŒํ•œ ํš๋“
    executeTask(i);
}

private static void executeTask(int taskId) {
    System.out.println("Executing task " + taskId);
    // ์‹ค์ œ ์ž‘์—… ์ˆ˜ํ–‰
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ดˆ๋‹น 2๊ฐœ์˜ ์ž‘์—…๋งŒ ์‹คํ–‰๋˜๋„๋ก ์ œํ•œํ•  ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ํ”„๋ฆฌ๋žœ์„œ๊ฐ€ ํ•œ ๋ฒˆ์— ๋„ˆ๋ฌด ๋งŽ์€ ์ž‘์—…์„ ๋ฐ›์ง€ ์•Š๋„๋ก ์ œํ•œํ•˜๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•ด! ๐Ÿ‘จโ€๐Ÿ’ป

4. ServiceManager

๋งˆ์ง€๋ง‰์œผ๋กœ ์†Œ๊ฐœํ•  ๊ธฐ๋Šฅ์€ ServiceManager์•ผ. ์ด ๋…€์„์€ ์—ฌ๋Ÿฌ ์„œ๋น„์Šค์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ผ. ์„œ๋น„์Šค์˜ ์‹œ์ž‘, ์ค‘์ง€, ์ƒํƒœ ํ™•์ธ ๋“ฑ์„ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์ง€.


import com.google.common.util.concurrent.AbstractService;
import com.google.common.util.concurrent.ServiceManager;

class MyService extends AbstractService {
    protected void doStart() { /* ์„œ๋น„์Šค ์‹œ์ž‘ ๋กœ์ง */ }
    protected void doStop() { /* ์„œ๋น„์Šค ์ค‘์ง€ ๋กœ์ง */ }
}

List<Service> services = Arrays.asList(new MyService(), new MyService());
ServiceManager manager = new ServiceManager(services);

manager.addListener(new ServiceManager.Listener() {
    public void healthy() {
        System.out.println("All services are running.");
    }
    public void stopped() {
        System.out.println("All services have stopped.");
    }
});

manager.startAsync();  // ๋ชจ๋“  ์„œ๋น„์Šค ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‹œ์ž‘

์™€! ์ด๋ ‡๊ฒŒ ์—ฌ๋Ÿฌ ์„œ๋น„์Šค๋ฅผ ํ•œ ๋ฒˆ์— ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์—ฌ๋Ÿฌ ํ”„๋ฆฌ๋žœ์„œ์˜ ์ž‘์—… ์ƒํƒœ๋ฅผ ํ•œ ๋ˆˆ์— ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ํŽธ๋ฆฌํ•˜์ง€? ๐Ÿ˜ƒ

์ž, ์ด๋ ‡๊ฒŒ Guava์˜ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด ์•Œ์•„๋ดค์–ด. ์ด ๊ธฐ๋Šฅ๋“ค์„ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ๋ณต์žกํ•œ ๋น„๋™๊ธฐ ์ž‘์—…์„ ํ›จ์”ฌ ์‰ฝ๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์—ฌ๋Ÿฌ ํ”„๋ฆฌ๋žœ์„œ์˜ ์ž‘์—…์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์•ผ. ์ด์ œ ์ด ๋…€์„๋“ค์„ ํ™œ์šฉํ•ด์„œ ๋” ๊ฐ•๋ ฅํ•˜๊ณ  ํšจ์œจ์ ์ธ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค์–ด๋ณด์ž๊ณ ! ๐Ÿ’ช

๐Ÿ“ Guava์˜ I/O ์œ ํ‹ธ๋ฆฌํ‹ฐ

์ž, ์ด์ œ Guava์˜ ๋งˆ์ง€๋ง‰ ์ฃผ์š” ๊ธฐ๋Šฅ์ธ I/O ์œ ํ‹ธ๋ฆฌํ‹ฐ์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฑฐ์•ผ. I/O๊ฐ€ ๋ญ๋ƒ๊ณ ? ์Œ... ์ƒ์ƒํ•ด๋ด. ๋„ค๊ฐ€ ์ฑ…์„ ์ฝ๊ณ (Input) ๊ทธ ๋‚ด์šฉ์„ ๋…ธํŠธ์— ์ ๋Š”(Output) ๊ฑธ ์ƒ๊ฐํ•ด๋ด. ๊ทธ๊ฒŒ ๋ฐ”๋กœ I/O์•ผ! ์ปดํ“จํ„ฐ์—์„œ๋Š” ํŒŒ์ผ์„ ์ฝ๊ณ  ์“ฐ๋Š” ๊ฑธ ๋งํ•˜์ง€. ๐Ÿ˜„

๐Ÿš€ Guava I/O ์œ ํ‹ธ๋ฆฌํ‹ฐ์˜ ์žฅ์ :

  • ๊ฐ„๊ฒฐํ•˜๊ณ  ์ฝ๊ธฐ ์‰ฌ์šด ์ฝ”๋“œ
  • ๋‹ค์–‘ํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ฉ”์„œ๋“œ ์ œ๊ณต
  • ์—๋Ÿฌ ์ฒ˜๋ฆฌ์˜ ๊ฐ„์†Œํ™”

Guava์˜ I/O ์œ ํ‹ธ๋ฆฌํ‹ฐ๋Š” ์ •๋ง ํŽธ๋ฆฌํ•ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ํ”„๋ฆฌ๋žœ์„œ๊ฐ€ ์ž‘์—… ๊ฒฐ๊ณผ๋ฌผ์„ ์‰ฝ๊ฒŒ ์—…๋กœ๋“œํ•˜๊ณ  ๋‹ค์šด๋กœ๋“œํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ํŒŒ์ผ ์ž‘์—…์„ ํ›จ์”ฌ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์ค˜.

1. Files ํด๋ž˜์Šค

Files ํด๋ž˜์Šค๋Š” ํŒŒ์ผ ๊ด€๋ จ ์ž‘์—…์„ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค์•ผ. ํŒŒ์ผ ์ฝ๊ธฐ, ์“ฐ๊ธฐ, ๋ณต์‚ฌ ๋“ฑ์˜ ์ž‘์—…์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์ง€.

Files ํด๋ž˜์Šค ๊ธฐ๋Šฅ Files Class Read Write Copy

์ž, ์ด์ œ ์ฝ”๋“œ๋กœ ํ•œ๋ฒˆ ๋ณผ๊นŒ?


import com.google.common.io.Files;
import java.io.File;
import java.nio.charset.StandardCharsets;

// ํŒŒ์ผ ์ฝ๊ธฐ
List<String> lines = Files.readLines(new File("input.txt"), StandardCharsets.UTF_8);

// ํŒŒ์ผ ์“ฐ๊ธฐ
Files.write("Hello, Guava!".getBytes(), new File("output.txt"));

// ํŒŒ์ผ ๋ณต์‚ฌ
Files.copy(new File("source.txt"), new File("destination.txt"));

์™€! ์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ํŒŒ์ผ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ํ”„๋ฆฌ๋žœ์„œ๊ฐ€ ์ž‘์—… ๊ฒฐ๊ณผ๋ฌผ์„ ์‰ฝ๊ฒŒ ์—…๋กœ๋“œํ•˜๊ณ  ๋‹ค์šด๋กœ๋“œํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ํŽธ๋ฆฌํ•˜์ง€? ๐Ÿ‘

2. ByteSource์™€ CharSource

ByteSource์™€ CharSource๋Š” ๋ฐ”์ดํŠธ ๋ฐ์ดํ„ฐ์™€ ๋ฌธ์ž ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ƒํ™”ํ•œ ํด๋ž˜์Šค์•ผ. ์ด ๋…€์„๋“ค์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ์˜ ์›์ฒœ์— ์ƒ๊ด€์—†์ด ์ผ๊ด€๋œ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ์–ด.


import com.google.common.io.ByteSource;
import com.google.common.io.CharSource;
import com.google.common.io.Files;

// ํŒŒ์ผ์—์„œ ByteSource ์ƒ์„ฑ
ByteSource byteSource = Files.asByteSource(new File("data.bin"));
byte[] bytes = byteSource.read();

// ๋ฌธ์ž์—ด์—์„œ CharSource ์ƒ์„ฑ
CharSource charSource = CharSource.wrap("Hello, Guava!");
String result = charSource.read();

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ฐ์ดํ„ฐ์˜ ์ถœ์ฒ˜์— ์ƒ๊ด€์—†์ด ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ํ˜•์‹์˜ ํฌํŠธํด๋ฆฌ์˜ค๋ฅผ ์ผ๊ด€๋œ ๋ฐฉ์‹์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ํŽธ๋ฆฌํ•˜์ง€? ๐Ÿ˜Ž

3. ByteSink์™€ CharSink

ByteSink์™€ CharSink๋Š” ByteSource์™€ CharSource์˜ ์“ฐ๊ธฐ ๋ฒ„์ „์ด์•ผ. ์ด ๋…€์„๋“ค์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ์“ฐ๋Š” ์ž‘์—…์„ ์ถ”์ƒํ™”ํ•  ์ˆ˜ ์žˆ์–ด.


import com.google.common.io.ByteSink;
import com.google.common.io.CharSink;
import com.google.common.io.Files;

// ํŒŒ์ผ์— ByteSink ์ƒ์„ฑ
ByteSink byteSink = Files.asByteSink(new File("output.bin"));
byteSink.write(new byte[]{1, 2, 3, 4, 5});

// ํŒŒ์ผ์— CharSink ์ƒ์„ฑ
CharSink charSink = Files.asCharSink(new File("output.txt"), StandardCharsets.UTF_8);
charSink.write("Hello, Guava!");

์™€์šฐ! ์ด๋ ‡๊ฒŒ ์‰ฝ๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์“ธ ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ํ”„๋ฆฌ๋žœ์„œ๊ฐ€ ๋‹ค์–‘ํ•œ ํ˜•์‹์˜ ๊ฒฐ๊ณผ๋ฌผ์„ ์‰ฝ๊ฒŒ ์—…๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ํŽธ๋ฆฌํ•˜์ง€? ๐Ÿ‘จโ€๐Ÿ’ป

4. ์ŠคํŠธ๋ฆผ ์œ ํ‹ธ๋ฆฌํ‹ฐ

Guava๋Š” ์ŠคํŠธ๋ฆผ ์ž‘์—…์„ ์œ„ํ•œ ๋‹ค์–‘ํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ฉ”์„œ๋“œ๋„ ์ œ๊ณตํ•ด. ์ด ๋…€์„๋“ค์„ ์‚ฌ์šฉํ•˜๋ฉด ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ๋ฅผ ๋”์šฑ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์–ด.


import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;
import java.io.InputStream;
import java.io.InputStreamReader;

// InputStream์„ byte ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜
byte[] bytes = ByteStreams.toByteArray(inputStream);

// Reader์˜ ๋‚ด์šฉ์„ ๋ฌธ์ž์—ด๋กœ ์ฝ๊ธฐ
String content = CharStreams.toString(new InputStreamReader(inputStream, StandardCharsets.UTF_8));

์ด๋ ‡๊ฒŒ ์ŠคํŠธ๋ฆผ ์ž‘์—…์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ์„ ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ํŽธ๋ฆฌํ•˜์ง€? ๐Ÿ˜ƒ

์ž, ์ด๋ ‡๊ฒŒ Guava์˜ I/O ์œ ํ‹ธ๋ฆฌํ‹ฐ์— ๋Œ€ํ•ด ์•Œ์•„๋ดค์–ด. ์ด ๊ธฐ๋Šฅ๋“ค์„ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ํŒŒ์ผ ์ฒ˜๋ฆฌ๋‚˜ ๋ฐ์ดํ„ฐ ์ž…์ถœ๋ ฅ ์ž‘์—…์„ ํ›จ์”ฌ ์‰ฝ๊ณ  ํšจ์œจ์ ์œผ๋กœ ํ•  ์ˆ˜ ์žˆ์–ด. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ํ˜•์‹์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์‰ฝ๊ฒŒ ๋‹ค๋ฃจ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์•ผ. ์ด์ œ ์ด ๋…€์„๋“ค์„ ํ™œ์šฉํ•ด์„œ ๋” ๊ฐ•๋ ฅํ•˜๊ณ  ํšจ์œจ์ ์ธ I/O ์ฒ˜๋ฆฌ๋ฅผ ํ•ด๋ณด์ž๊ณ ! ๐Ÿ’ช

๐ŸŽญ Guava: ๊ฒฐ๋ก  ๋ฐ ๋งˆ๋ฌด๋ฆฌ

์ž, ์šฐ๋ฆฌ์˜ Guava ์—ฌํ–‰์ด ๊ฑฐ์˜ ๋๋‚˜๊ฐ€๊ณ  ์žˆ์–ด. ์ •๋ง ๋ฉ‹์ง„ ์—ฌ์ •์ด์—ˆ์ง€? ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ์„ ๊ฐ€์ง„ ํ”„๋ฆฌ๋žœ์„œ๋“ค์„ ๋งŒ๋‚˜๋ณธ ๊ฒƒ ๊ฐ™์•„. ๐Ÿ˜Š

๐ŸŒŸ Guava์˜ ์ฃผ์š” ์žฅ์ :

  • ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ ํ–ฅ์ƒ
  • ์ƒ์‚ฐ์„ฑ ์ฆ๊ฐ€
  • ๋ฒ„๊ทธ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ ๊ฐ์†Œ
  • ์„ฑ๋Šฅ ์ตœ์ ํ™”

Guava๋Š” ์ •๋ง ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์•ผ. ์ปฌ๋ ‰์…˜, ์บ์‹ฑ, ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ, I/O ๋“ฑ ๋‹ค์–‘ํ•œ ์˜์—ญ์—์„œ ์šฐ๋ฆฌ์˜ ์ฝ”๋”ฉ ์ƒํ™œ์„ ๋”์šฑ ํŽธ๋ฆฌํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ค˜. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์ด ํ”„๋ฆฌ๋žœ์„œ์™€ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, Guava๋Š” ์šฐ๋ฆฌ์™€ ํšจ์œจ์ ์ธ ์ฝ”๋”ฉ์„ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ๋‹ค๋ฆฌ ์—ญํ• ์„ ํ•˜์ง€.

ํ•˜์ง€๋งŒ ๊ธฐ์–ตํ•ด์•ผ ํ•  ์ ์€, Guava๋„ ๊ฒฐ๊ตญ์€ ๋„๊ตฌ์ผ ๋ฟ์ด๋ผ๋Š” ๊ฑฐ์•ผ. ์ค‘์š”ํ•œ ๊ฑด ์ด ๋„๊ตฌ๋ฅผ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•˜๋Š๋ƒ์•ผ. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ž์‹ ์˜ ์žฌ๋Šฅ์„ ์–ด๋–ป๊ฒŒ ํ‘œํ˜„ํ•˜๊ณ  ํ™œ์šฉํ•˜๋Š๋ƒ๊ฐ€ ์ค‘์š”ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์•ผ.

๊ทธ๋Ÿฌ๋‹ˆ Guava๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํ•ญ์ƒ ์ด๋Ÿฐ ์งˆ๋ฌธ์„ ํ•ด๋ณด์ž:

  • ์ด ๊ธฐ๋Šฅ์ด ๋‚ด ์ฝ”๋“œ๋ฅผ ๋” ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋‚˜?
  • ์ด ๊ธฐ๋Šฅ์ด ๋‚ด ์ฝ”๋“œ์˜ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œ์ผœ์ฃผ๋‚˜?
  • ์ด ๊ธฐ๋Šฅ์ด ๋‚ด ์ฝ”๋“œ์˜ ์•ˆ์ •์„ฑ์„ ๋†’์—ฌ์ฃผ๋‚˜?

์ด๋Ÿฐ ์งˆ๋ฌธ๋“ค์— "์˜ˆ"๋ผ๊ณ  ๋‹ตํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ์ฃผ์ € ์—†์ด Guava๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์ž๊ณ !

์ž, ์ด์ œ ์šฐ๋ฆฌ์˜ Guava ์—ฌํ–‰์ด ๋๋‚ฌ์–ด. ํ•˜์ง€๋งŒ ์ด๊ฒŒ ๋์ด ์•„๋‹ˆ์•ผ. ์ด์ œ๋ถ€ํ„ฐ๊ฐ€ ์ง„์งœ ์‹œ์ž‘์ด์ง€. Guava๋ฅผ ํ™œ์šฉํ•ด์„œ ๋” ๋ฉ‹์ง„ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ๋” ํšจ์œจ์ ์ธ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค์–ด๋ณด์ž. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ƒˆ๋กœ์šด ๊ธฐํšŒ๋ฅผ ๋ฐœ๊ฒฌํ•˜๊ณ  ์„ฑ์žฅํ•ด๋‚˜๊ฐ€๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์•ผ.

์ฝ”๋”ฉ์˜ ์„ธ๊ณ„๋Š” ๋„“๊ณ  ๊นŠ์–ด. Guava๋Š” ๊ทธ ์„ธ๊ณ„๋ฅผ ํƒํ—˜ํ•˜๋Š” ๋ฐ ๋„์›€์„ ์ฃผ๋Š” ํ›Œ๋ฅญํ•œ ๋„๊ตฌ์•ผ. ์ด ๋„๊ตฌ๋ฅผ ์ž˜ ํ™œ์šฉํ•ด์„œ ์ž๋ฐ” ๊ฐœ๋ฐœ์˜ ๋‹ฌ์ธ์ด ๋˜์–ด๋ณด์ž๊ณ ! ํ™”์ดํŒ…! ๐Ÿ’ช๐Ÿ˜„