Post

๐Ÿฃ chap8. ์ปฌ๋ ‰์…˜ API ๊ฐœ์„ 

8.1 ์ปฌ๋ ‰์…˜ ํŒฉํ† ๋ฆฌ

A, B, C๋ฅผ ํฌํ•จํ•˜๋Š” ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“ ๋‹ค.

1
2
3
4
List<String> friends = new ArrayList<>();
friends.add("A");
friends.add("B");
friends.add("C");
1
List<String> friends = Arrays.asList("A", "B", "C");

UnsupportedOperationException ์˜ˆ์™ธ ๋ฐœ์ƒ

1
friends.add("D");

๊ณ ์ • ํฌ๊ธฐ ๋ฐฐ์—ด๋กœ ๋งŒ๋“ค์–ด์ง

Set ๋งŒ๋“ค๊ธฐ

1
2
3
Set<String> friends = new HashSet<>(
Arrays.asList("A", "B", "C")
);

ํ˜น์€ stream API๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

1
2
Set<String> friends = Stream.of("A", "B", "C")
.collect(Collectors.toSet());

๋‘ ๋ฐฉ๋ฒ• ๋ชจ๋‘ ๋ถˆํ•„์š”ํ•œ ๋‹จ๊ณ„ ํ•˜๋‚˜์”ฉ์„ ๊ฑด๋„ˆ์•ผ ํ•˜๊ณ , ๋งค๋„๋Ÿฝ์ง€ ๋ชปํ•˜๊ณ  ๋‚ด๋ถ€์ ์œผ๋กœ ๋ถˆํ•„์š”ํ•œ ๊ฐ์ฒด ํ• ๋‹น์„ ํ•„์š”๋กœ ํ•œ๋‹ค.

์ž๋ฐ”9์—์„œ ๋ฆฌ์ŠคํŠธ, ์ง‘ํ•ฉ, ๋งต์„ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š”ย ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•จ

8.1.1 ๋ฆฌ์ŠคํŠธ ํŒฉํ† ๋ฆฌ

List.of

1
2
List<String> friends = List.of("A", "B", "C");
System.out.println(friends);
  • add๋ฅผ ํ•˜๋ฉด ์—๋Ÿฌ ๋ฐœ์ƒ
  • ์œ„ ๋ฆฌ์ŠคํŠธ๋Š” ๋ถˆ๋ณ€ ๋ฆฌ์ŠคํŠธ
  • set() X
  • null ์š”์†Œ๋„ ๋ถˆ๊ฐ€

์˜ค๋ฒ„๋กœ๋”ฉ

1
2
3
static <E> List<E> of(E e1, E e2, E e3);
static <E> List<E> of(E e1, E e2, E e3, E e4);
static <E> List<E> of(E... elements);

์ตœ์ ํ™”๋ฅผ ์œ„ํ•œ ์˜ค๋ฒ„๋กœ๋”ฉ

8.1.2 ์ง‘ํ•ฉ ํŒฉํ† ๋ฆฌ

1
2
3
Set<String> friends = Set.of("A", "B", "C");

System.out.println(friends);

of ๋ฅผ ํ†ตํ•ด ์ œ๊ณตํ•œ ์š”์†Œ ์ค‘ ์ค‘๋ณต์ด ์žˆ์œผ๋ฉด IllegalArgumentException ๋ฆฌํ„ด

8.1.3 ๋งต ํŒฉํ† ๋ฆฌ

1
2
Map<String, Integer> ageOfFriends =
Map.of("A", 1, "B", 2, "C", 3);

10๊ฐœ ์ดํ•˜์˜ ํ‚ค์™€ ๊ฐ’ ์Œ์„ ๊ฐ€์ง„ ์ž‘์€ ๋งต ์œ ์šฉ

10๊ฐœ ์ด์ƒ์˜ ๋งต์€ Map.Entry<K, V> ๊ฐ์ฒด๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š” ๊ฐ€๋ณ€ ์ธ์ˆ˜๋กœ ๊ตฌํ˜„๋œ Map.ofEntries ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉ

1
2
3
4
5
6
7
import static java.util.Map.entry;

Map<String, Integer> ageOfFriends = Map.ofEntries(
entry("A", 1),
entry("B", 2),
entry("C", 3)
);

8.2 ๋ฆฌ์ŠคํŠธ์™€ ์ง‘ํ•ฉ ์ฒ˜๋ฆฌ

์ž๋ฐ” 8์—์„œ๋Š” List, Set ์ธํ„ฐํŽ˜์ด์Šค์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

  • removeIf : ํ”„๋ ˆ๋””์ผ€์ดํŠธ๋ฅผ ๋งŒ์กฑํ•˜๋Š” ์š”์†Œ๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.
  • replaceAll : UnaryOperator ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์š”์†Œ๋ฅผ ๋ฐ”๊พผ๋‹ค. ๋ฆฌ์ŠคํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • sort : ๋ฆฌ์ŠคํŠธ๋ฅผ ์ •๋ ฌํ•œ๋‹ค.

์ด ๋ฉ”์„œ๋“œ๋Š” ์ƒˆ๋กœ์šด ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“œ๋Š” ์ŠคํŠธ๋ฆผ ๋™์ž‘๊ณผ ๋‹ฌ๋ฆฌ ํ˜ธ์ถœํ•œ ๊ธฐ์กด ์ปฌ๋ ‰์…˜ ์ž์ฒด๋ฅผ ๋ฐ”๊พผ๋‹ค.

์ปฌ๋ ‰์…˜์„ ๋ฐ”๊พธ๋Š” ๋™์ž‘์€ ์—๋Ÿฌ๋ฅผ ์œ ๋ฐœํ•˜๋ฉฐ ๋ณต์žกํ•จ์„ ๋”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž๋ฐ” 8์—์„œ๋Š” removeIf์™€ replaceAll์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

8.2.1 removeIf ๋ฉ”์„œ๋“œ

๋‹ค์Œ์€ ์ˆซ์ž๋กœ ์‹œ์ž‘๋˜๋Š” ์ฐธ์กฐ ์ฝ”๋“œ๋ฅผ ๊ฐ€์ง„ ํŠธ๋žœ์žญ์…˜์„ ์‚ญ์ œํ•˜๋Š” ์ฝ”๋“œ๋‹ค.

1
2
3
4
5
for(Transaction transaction : transactions) {
  if(Character.isDigit(transaction.getReferenceCode().charAt(0))) {
    transaction.remove(transaction);
  }
}

์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด๋ณด๋ฉด ConcurrentModificationException์„ ์ผ์œผํ‚จ๋‹ค.

forEach ๋ฃจํ”„๋Š” Iterator ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ์œ„ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ด์„๋œ๋‹ค.

1
2
3
4
5
6
7
for(Iterator<Transaction> iterator = transactions.iterator(); iterator.hasNext(); ) {
  Transaction transaction = iterator.next();
  if(Character.isDigit(transaction.getReferenceCode().charAt(0))) {
    transactions.remove(transaction);
    // ๋ฐ˜๋ณต์ž๋ฅผ ์‚ฌ์šฉํ•ด ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ, ๋ฆฌ์ŠคํŠธ๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜๊ณ  ์žˆ์Œ -> ๋ฌธ์ œ ๋ฐœ์ƒ
  }
}

Iterator ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ์†Œ์Šค๋ฅผ ์งˆ์˜ํ•˜๊ณ , Collection ๊ฐ์ฒด ์ž์ฒด์— remove()๋ฅผ ํ˜ธ์ถœํ•ด ์š”์†Œ๋ฅผ ์‚ญ์ œํ•˜๊ณ  ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋ฐ˜๋ณต์ž์˜ ์ƒํƒœ์™€ ์ปฌ๋ ‰์…˜์˜ ์ƒํƒœ๊ฐ€ ๋™๊ธฐํ™”๋˜์ง€ ์•Š๋Š”๋‹ค.

Iterator ๊ฐ์ฒด๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ๊ทธ ๊ฐ์ฒด์˜ remove() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์ค˜์•ผ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

1
2
3
4
5
6
for(Iterator<Transaction> iterator = transactions.iterator(); iterator.hasNext(); ) {
  Transaction transaction = iterator.next();
  if(Character.isDigit(transaction.getReferenceCode().charAt(0))) {
    iterator.remove();
  }
}

์œ„์˜ ๋ณต์žกํ•œ ์ฝ”๋“œ ํŒจํ„ด์€ ์ž๋ฐ” 8์˜ removeIf ๋ฉ”์„œ๋“œ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค. removeIf๋Š” ์‚ญ์ œํ•  ์š”์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํ”„๋ ˆ๋””์ผ€์ดํŠธ๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค.

1
2
transactions.removeIf(transaction ->
  Character.isDigit(transaction.getReferenceCode().charAt(0))); // True์ธ ๊ฒฝ์šฐ ์ œ๊ฑฐ

8.2.2 replaceAll ๋ฉ”์„œ๋“œ

replaceIf์ฒ˜๋Ÿผ ์š”์†Œ๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ๋ฐ”๊ฟ”์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ผ ๋•Œ, replaceAll์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

List ์ธํ„ฐํŽ˜์ด์Šค์˜ replaceAll ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด ๋ฆฌ์ŠคํŠธ์˜ ๊ฐ ์š”์†Œ๋ฅผ ์ƒˆ๋กœ์šด ์š”์†Œ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค.

์•„๋ž˜๋Š” ์ŠคํŠธ๋ฆผ API๋ฅผ ์‚ฌ์šฉํ•œ ์˜ˆ์ œ์ด๋‹ค.

1
2
3
4
5
referenceCodes.stream() // [a12, C14, b13]
    .map(code -> Character.toUpperCase(code.charAt(0)) + code.subString(1))
    // ์ŠคํŠธ๋ฆผ์˜ ๊ฐ ์š”์†Œ์— ๋Œ€ํ•ด ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•˜์—ฌ ์ƒˆ๋กœ์šด ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑ
    .collect(Collectors.toList())
    .forEach(System.out::println);
1
2
3
4
5
// ๊ฒฐ๊ณผ
A12
C14
B13

ํ•˜์ง€๋งŒ ์ด ์ฝ”๋“œ๋Š” ์ƒˆ ๋ฌธ์ž์—ด ์ปฌ๋ ‰์…˜์„ ๋งŒ๋“ ๋‹ค. ๊ธฐ์กด ์ปฌ๋ ‰์…˜์„ ๋ฐ”๊พธ๋ ค๋ฉด ListIterator ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค.

1
2
3
4
5
for(ListIterator<String> iterator = referenceCodes.listIterator(); iterator.hasNext(); ) {
  String code = iterator.next();
  iterator.set(Character.toUpperCase(code.charAt(0)) + code.substring(1));
  // ๋ณ€๊ฒฝ๋œ ๊ฐ’์„ iterator.set() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜„์žฌ ์š”์†Œ์— ๋Œ€์ž…ํ•˜์—ฌ ์ˆ˜์ •
}

์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์กŒ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด์ฒ˜๋Ÿผ ์ปฌ๋ ‰์…˜ ๊ฐ์ฒด์™€ Iterator ๊ฐ์ฒด๋ฅผ ํ˜ผ์šฉํ•˜๋ฉด ๋ฐ˜๋ณต๊ณผ ๋ณ€๊ฒฝ์ด ๋™์‹œ์— ์ด๋ฃจ์–ด์ ธ ์‰ฝ๊ฒŒ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚จ๋‹ค.

์ž๋ฐ” 8์˜ replaceAll ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

1
referenceCodes.replaceAll(code -> Character.toUpperCase(code.charAt(0)) + code.substring(1));

๋‹ค์Œ 8.3์ ˆ์—์„œ๋Š” Map ์ธํ„ฐํŽ˜์ด์Šค์— ์ถ”๊ฐ€๋œ ์ƒˆ ๊ธฐ๋Šฅ์„ ์„ค๋ช…ํ•œ๋‹ค.

8.3. ๋งต ์ฒ˜๋ฆฌ

์ž๋ฐ” 8์—์„œ๋Š” Map ์ธํ„ฐํŽ˜์ด์Šค์— ๋””ํดํŠธ ๋ฉ”์†Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

8.3.1. forEach ๋ฉ”์†Œ๋“œ

๋งต์—์„œ ํ‚ค์™€ ๊ฐ’์„ ๋ฐ˜๋ณตํ•˜๋Š” ์ž‘์—…์„ ์œ„ํ•ด ์ž๋ฐ” 8์—์„œ๋ถ€ํ„ฐ Map ์ธํ„ฐํŽ˜์ด์Šค๋Š” BiConsumer(ํ‚ค์™€ ๊ฐ’์„ ์ธ์ˆ˜๋กœ ๋ฐ›์Œ)๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š”ย forEachย ๋ฉ”์†Œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
// forEach ๋ฉ”์†Œ๋“œ ๋ฏธ์‚ฌ์šฉ
for (Map.Entry<String, Integer> entry : ageOfFriends.entrySet()) {
    String friend = entry.getKey();
    Integer age = entry.getValue();
    System.out.println(friend + " is " + age + " years old");
}

// forEach ๋ฉ”์†Œ๋“œ ์‚ฌ์šฉ
ageOfFriends.forEach((friend, age) -> System.out.println(friend + " is " + age + " years old"));

8.3.2 ์ •๋ ฌ ๋ฉ”์†Œ๋“œ

Entry.comparingByValue,ย Entry.comparingByKey๋ฅผ ์ด์šฉํ•˜๋ฉด ๋งต์˜ ํ•ญ๋ชฉ์„ ๊ฐ’ ๋˜๋Š” ํ‚ค๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
3
4
5
6
7
8
Map<String, String> favouriteMovies = Map.ofEntries(entry("Raphael", "Star Wars"),
        entry("Cristina", "Matrix"),
        entry("Olivia", "James Bond"));

favouriteMovies.entrySet()
        .stream()
        .sorted(Entry.comparingByKey()) // ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์•ŒํŒŒ๋ฒณ ์ˆœ์œผ๋กœ ์ŠคํŠธ๋ฆผ ์š”์†Œ ์ฒ˜๋ฆฌ
        .forEachOrdered(System.out::println);

HashMap ์„ฑ๋Šฅ

์ž๋ฐ” 8์—์„œ๋Š” HashMap์˜ ๋‚ด๋ถ€ ๊ตฌ์กฐ๋ฅผ ๋ฐ”๊ฟ” ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ–ˆ๋‹ค.

๊ธฐ์กด์˜ ๋งต์˜ ํ•ญ๋ชฉ์€ ๋งŽ์€ ํ‚ค๊ฐ€ ๊ฐ™์€ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ƒํ™ฉ์ด ๋˜๋ฉด O(n)์˜ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋Š” LinkedList๋กœ ๋ฒ„ํ‚ท์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์„ฑ๋Šฅ์ด ์ €ํ•˜๋˜์—ˆ๋‹ค.

์ตœ๊ทผ์—๋Š” ๋ฒ„ํ‚ท์ด ๋„ˆ๋ฌด ์ปค์ง€๋ฉด O(log(n))์˜ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๋Š” ์ •๋ ฌ๋œ ํŠธ๋ฆฌ๋ฅผ ์ด์šฉํ•ด ๋™์ ์œผ๋กœ ์น˜ํ™˜ํ•ด ์ถฉ๋Œ์ด ์ผ์–ด๋‚˜๋Š” ์š”์†Œ ๋ฐ˜ํ™˜ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ–ˆ๋‹ค. (ํ‚ค๊ฐ€ Comparable ํ˜•ํƒœ์—ฌ์•ผ ์ •๋ ฌ๋œ ํŠธ๋ฆฌ๋ฅผ ์ง€์›)

8.3.3 getOrDefault ๋ฉ”์„œ๋“œ

ํ‚ค๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ๊ฒฐ๊ณผ๊ฐ€ null์ด ๋ฐ˜ํ™˜๋˜๋ฏ€๋กœ NullPointerException์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์š”์ฒญ ๊ฒฐ๊ณผ์˜ null ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•ด์•ผ ํ–ˆ๋‹ค.

๊ธฐ๋ณธ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š”ย getOrDefaultย ๋ฉ”์„œ๋“œ๋Š” ์ฒซ ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ํ‚ค๋ฅผ, ๋‘ ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ๊ธฐ๋ณธ๊ฐ’์„ ๋ฐ›์•„ ๋งต์— ํ‚ค๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ๋‘ ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ๋ฐ›์€ ๊ธฐ๋ณธ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

1
2
3
4
Map<String, String> favouriteMovies = Map.ofEntries(entry("Raphael", "Star Wars"), entry("Olivia", "James Bond"));

System.out.println(favouriteMovies.getOrDefault("Olivia", "Matrix"));   // James Bond ์ถœ๋ ฅ
System.out.println(favouriteMovies.getOrDefault("Thibaut", "Matrix"));  // Matrix ์ถœ๋ ฅ

ํ‚ค๊ฐ€ ์กด์žฌํ•˜๋”๋ผ๋„ ๊ฐ’์ด null์ธ ์ƒํ™ฉ์—์„œ๋Š”ย getOrDefault๊ฐ€ null์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

8.3.4 ๊ณ„์‚ฐ ํŒจํ„ด

ํ‚ค ์กด์žฌ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ์–ด๋–ค ๋™์ž‘์„ ์‹คํ–‰ํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์ด ํ•„์š”ํ•œ ๋•Œ๊ฐ€ ์žˆ๋‹ค.

๋‹ค์Œ์˜ 3๊ฐ€์ง€ ์—ฐ์‚ฐ์ด ์ด๋Ÿฐ ์ƒํ™ฉ์— ๋„์›€์ด ๋œ๋‹ค.

  • computeIfAbsentย : ์ œ๊ณต๋œ ํ‚ค์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์ด ์—†์œผ๋ฉด(ํ˜น์€ null) ํ‚ค๋ฅผ ์ด์šฉํ•ด ์ƒˆ ๊ฐ’์„ ๊ณ„์‚ฐํ•˜๊ณ  ๋งต์— ์ถ”๊ฐ€ํ•œ๋‹ค.
  • computeIfPresentย : ์ œ๊ณต๋œ ํ‚ค๊ฐ€ ์กด์žฌํ•˜๋ฉด ์ƒˆ ๊ฐ’์„ ๊ณ„์‚ฐํ•˜๊ณ  ๋งต์— ์ถ”๊ฐ€ํ•œ๋‹ค.
  • computeย : ์ œ๊ณต๋œ ํ‚ค๋กœ ์ƒˆ ๊ฐ’์„ ๊ณ„์‚ฐํ•˜๊ณ  ๋งต์— ์ €์žฅํ•œ๋‹ค.
  • Map์„ ์ด์šฉํ•œ ์บ์‹œ ๊ตฌํ˜„
1
2
3
4
5
6
7
8
9
10
11
12
13
// ์บ์‹œ
Map<String, byte[]> dataToHash = new HashMap<>();

// ๊ฐ ๋ผ์ธ์„ SHA-256์˜ ํ•ด์‹œ ๊ฐ’์œผ๋กœ ๊ณ„์‚ฐํ•ด์„œ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ๊ณ„์‚ฐ ๊ฐ์ฒด
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");

// ํ‚ค๊ฐ€ ์—†๋‹ค๋ฉด line๊ณผ ๊ณ„์‚ฐ๋œ ํ•ด์‹œ ๊ฐ’์ด key,value๋กœ ๋“ค์–ด๊ฐ
lines.forEach(line -> dataToHash.computeIfAbsent(line, this::calculateDigest));

// ํ‚ค์˜ ํ•ด์‹œ๋ฅผ ๊ณ„์‚ฐํ•ด์„œ ๋ฐ˜ํ™˜
private byte[] calculateDigest(String key) {
    return messageDigest.digest(key.getBytes(StandardCharsets.UTF_8));
}
  • ํ‚ค๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ๊ฐ’์„ ๋ฐ˜ํ™˜

์•„๋ž˜ ์ฝ”๋“œ๋Š” ํ‚ค๊ฐ€ ์กด์žฌํ•˜๋ฉด ๊ธฐ์กด ๊ฐ’์—, ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์ƒˆ๋กœ์šด ๋ฆฌ์ŠคํŠธ์— โ€˜Star Warsโ€™๊ฐ€ ์ถ”๊ฐ€ ๋œ๋‹ค.

1
2
friendsToMovies.computeIfAbsent("Raphael", name -> new ArrayList<>())
        .add("Star Wars");

8.3.5 ์‚ญ์ œ ํŒจํ„ด

์ž๋ฐ” 8์—์„œ๋Š” ํ‚ค๊ฐ€ ํŠน์ •ํ•œ ๊ฐ’๊ณผ ์—ฐ๊ด€๋˜์—ˆ์„ ๋•Œ๋งŒ ํ•ญ๋ชฉ์„ ์ œ๊ฑฐํ•˜๋Š” ์˜ค๋ฒ„๋กœ๋“œ ๋ฒ„์ „ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

  • ์ž๋ฐ” 8 ์ด์ „
1
2
3
4
5
6
7
8
String key = "Raphael";
String value = "Jack Reacher 2";
if (favouriteMovies.containsKey(key) && Objects.equals(favouriteMovies.get(key), value)) {
   favouriteMovies.remove(key);
   return true;
} else {
   return false;
}
  • ์ž๋ฐ” 8 ์ดํ›„
1
favouriteMovies.remove(key, value);

8.3.6 ๊ต์ฒด ํŒจํ„ด

๋งต์˜ ํ•ญ๋ชฉ์„ ๋ฐ”๊พธ๋Š”๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ

  • replaceAllย : BiFunction์„ ์ ์šฉํ•œ ๊ฒฐ๊ณผ๋กœ ๊ฐ ํ•ญ๋ชฉ์˜ ๊ฐ’์„ ๊ต์ฒดํ•œ๋‹ค.
  • replaceย : ํ‚ค๊ฐ€ ์กด์žฌํ•˜๋ฉด ๋งต์˜ ๊ฐ’์„ ๋ฐ”๊พผ๋‹ค. ํ‚ค๊ฐ€ ํŠน์ • ๊ฐ’์œผ๋กœ ๋งคํ•‘๋˜์—ˆ์„ ๋•Œ๋งŒ ๊ฐ’์„ ๊ต์ฒดํ•˜๋Š” ์˜ค๋ฒ„๋กœ๋“œ ๋ฒ„์ „๋„ ์žˆ๋‹ค.
1
2
3
4
5
Map<String, String> favouriteMovies = new HashMap<>();
favouriteMovies.put("Raphael", "Star Wars");
favouriteMovies.put("Olivia", "james bond");

favouriteMovies.replaceAll((friend, movie) -> movie.toUpperCase());

8.3.7 ํ•ฉ์นจ

putAllย ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋‘ ๋งต์„ ํ•ฉ์น  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ย putAll์€ ์ค‘๋ณต๋œ ํ‚ค๊ฐ€ ์žˆ๋‹ค๋ฉด ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค.

์ด๋•Œ๋Š” ์ค‘๋ณต๋œ ํ‚ค๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ฉ์น ์ง€ ๊ฒฐ์ •ํ•˜๋Š”ย BiFunction์„ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š” mergeย ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉ

  • putAll ์‚ฌ์šฉ
1
2
3
4
5
Map<String, String> family = Map.ofEntries(entry("Teo", "Star Wars"), entry("Cristina", "James Bond"));
Map<String, String> friends = Map.ofEntries(entry("Raphael", "Star Wars"));

Map<String, String> everyone = new HashMap<>(family);
everyone.putAll(friends);
  • merge ์‚ฌ์šฉ

์ค‘๋ณต๋œ ํ‚ค๊ฐ€ ์žˆ์œผ๋ฉด ๋‘ ๊ฐ’์„ ์—ฐ๊ฒฐํ•˜๊ณ  ์—†์œผ๋ฉด (key, value) ๊ทธ๋Œ€๋กœ ์ €์žฅํ•œ๋‹ค.

1
2
3
Map<String, String> everyone = new HashMap<>(family);
friends.forEach((key, value) -> everyone.merge(key, value, (movie1, movie2) -> movie1 + " & " + movie2));
System.out.println(everyone);
  • merge๋ฅผ ์ด์šฉํ•œ ์ดˆ๊ธฐํ™” ๊ฒ€์‚ฌ

์›ํ•˜๋Š” ๊ฐ’์ด ์ดˆ๊ธฐํ™”๋˜์–ด ์žˆ์œผ๋ฉด +1, ์ดˆ๊ธฐํ™” ๋˜์–ด์žˆ์ง€ ์•Š์•„ null์ด๋ฉด (movieName, 1) ์ €์žฅํ•œ๋‹ค.

1
moviesToCount.merge(movieName, 1L, (key, count) -> count + 1L);

8.4 ๊ฐœ์„ ๋œ ConcurrentHashMap

ConcurrentHashMap

  • ๋™์‹œ์„ฑ ์นœํ™”์ ์ด๋ฉฐย ์ตœ์‹  ๊ธฐ์ˆ ์„ ๋ฐ˜์˜ํ•œ HashMap ๋ฒ„์ „
  • ๋‚ด๋ถ€ ์ž๋ฃŒ๊ตฌ์กฐ์˜ย ํŠน์ • ๋ถ€๋ถ„๋งŒ ์ž ๊ฐ€ย ๋™์‹œ ์ถ”๊ฐ€, ๊ฐฑ์‹  ์ž‘์—…์„ ํ—ˆ์šฉํ•จ
  • ๋™๊ธฐํ™”๋œ Hashtable ๋ฒ„์ „์— ๋น„ํ•ดย ์ฝ๊ธฐ/์“ฐ๊ธฐ ์—ฐ์‚ฐ ์„ฑ๋Šฅ์ด ์›”๋“ฑํ•˜๋‹ค
  • (์ฐธ๊ณ ๋กœ, ํ‘œ์ค€ HashMap์€ ๋น„๋™๊ธฐ๋กœ ๋™์ž‘ํ•จ)
1
2
3
4
5
6
7
8
9
10
11
12
13
public class ConcurrentHashMap<K,V> extends AbstractMap<K,V> implements ConcurrentMap<K,V>, Serializable {

	public V get(Object key) {}

	public boolean containsKey(Object key) { }

	public V put(K key, V value) {
		return putVal(key, value, false);
	}

	...

}

์ฐธ๊ณ  : Hashtable Class

1
2
3
4
5
6
7
8
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable {

	public synchronized int size() { }

	@SuppressWarnings("unchecked")
	public synchronized V get(Object key) { }

	public synchronized V put(K key, V value) { } }
  • ๋ฉ”์†Œ๋“œ ์ „์ฒด์—ย synchronizedย ํ‚ค์›Œ๋“œ๊ฐ€ ์กด์žฌ (๋ฉ”์†Œ๋“œ ์ „์ฒด๊ฐ€ ์ž„๊ณ„๊ตฌ์—ญ์œผ๋กœ ์„ค์ •๋จ)
  • ๋‹ค๋งŒ, ๋™์‹œ์— ์ž‘์—…์„ ํ•˜๋ คํ•ด๋„ ๊ฐ์ฒด๋งˆ๋‹ค Lock์„ ํ•˜๋‚˜์”ฉ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋™์‹œ์— ์—ฌ๋Ÿฌ ์ž‘์—…์„ ํ•ด์•ผํ•  ๋•Œ ๋ณ‘๋ชฉํ˜„์ƒ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ๋ฐ–์— ์—†์Œ

์ฐธ๊ณ  : HashMap

1
2
3
4
5
6
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {

	public V get(Object key) {}
	public V put(K key, V value) {}

}
  • synchronizedย ํ‚ค์›Œ๋“œ๊ฐ€ย ์กด์žฌํ•˜์ง€ ์•Š์Œ
  • Mapย ์ธํ„ฐํŽ˜์ด์Šค๋ฅผย ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค ์ค‘์—์„œ ์„ฑ๋Šฅ์ด ์ œ์ผ ์ข‹๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ์Œ
  • Multi-Threadย ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ํŠน์ง•

8.4.1. ์—ฐ์‚ฐ

  • forEachย : ๊ฐ key-value ์Œ์— ์ฃผ์–ด์ง„ ์•ก์…˜์„ ์ˆ˜ํ–‰
  • reduceย : ๋ชจ๋“  key-value ์Œ์„ ์ œ๊ณต๋œ reduce ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ๊ฒฐ๊ณผ๋กœ ํ•ฉ์นจ
  • searchย : null์ด ์•„๋‹Œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ๋•Œ๊นŒ์ง€ ๊ฐ key-value ์Œ์— ํ•จ์ˆ˜๋ฅผ ์ ์šฉ

์—ฐ์‚ฐ์˜ ์ข…๋ฅ˜

  • key-value๋กœ ์—ฐ์‚ฐ :ย forEach,ย reduce,ย search
  • key๋กœ ์—ฐ์‚ฐ :ย forEachKey,ย reduceKeys,ย searchKeys
  • value๋กœ ์—ฐ์‚ฐ :ย forEachValue,ย reduceValues,ย searchValues
  • Map.Entry๋กœ ์—ฐ์‚ฐ :ย forEachEntry,ย reduceEntries,ย searchEntries

์—ฐ์‚ฐ์‹œ ์œ ์˜์‚ฌํ•ญ

  • ์•„๋ž˜์˜ ์—ฐ์‚ฐ๋“ค์€ ConcurrentHashMap์˜ ์ƒํƒœ๋ฅผ ์ž ๊ทธ์ง€ ์•Š๊ณ  ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ โ†’ ์—ฐ์‚ฐ์— ์ œ๊ณตํ•œ ํ•จ์ˆ˜๋Š”ย ๊ณ„์‚ฐ์ด ์ง„ํ–‰๋˜๋Š” ๋™์•ˆ ๋ฐ”๋€” ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด, ๊ฐ’, ์ˆœ์„œ ๋“ฑ์— ์˜์กดํ•˜์ง€ ์•Š์•„์•ผ ํ•จ
  • ๋ณ‘๋ ฌ์„ฑ ๊ธฐ์ค€๊ฐ’(threshold)๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•จ
    • ๋งต์˜ ํฌ๊ธฐ๊ฐ€ ์ฃผ์–ด์ง„ ๊ธฐ์ค€๊ฐ’๋ณด๋‹ค ์ž‘์œผ๋ฉด ์ˆœ์ฐจ์ ์œผ๋กœ ์—ฐ์‚ฐ์„ ์‹คํ–‰ํ•จ
    • ๊ธฐ์ค€๊ฐ’ = 1ย : ๊ณตํ†ต ์Šค๋ ˆ๋“œ ํ’€์„ ์ด์šฉํ•ด ๋ณ‘๋ ฌ์„ฑ์„ ๊ทน๋Œ€ํ™”ํ•จ
    • ๊ธฐ์ค€๊ฐ’ = Long.MAX_VALUEย : ํ•œ ๊ฐœ์˜ ์Šค๋ ˆ๋“œ๋กœ ์—ฐ์‚ฐ์„ ์‹คํ–‰ํ•จ
    • (SW ์•„ํ‚คํ…์ฒ˜๊ฐ€ ๊ณ ๊ธ‰ ์ˆ˜์ค€์˜ ์ตœ์ ํ™”๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด) ๊ธฐ์ค€๊ฐ’ ๊ทœ์น™์„ ๋”ฐ๋ฅด๋Š” ๊ฒƒ์ด ์ข‹์Œ
      1
      2
      3
      4
      
      public class ConcurrentHashMap<K,V> extends AbstractMap<K,V> implements ConcurrentMap<K,V>, Serializable {
        private static final int DEFAULT_CAPACITY = 16; // ๋™์‹œ์— ์—…๋ฐ์ดํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์“ฐ๋ ˆ๋“œ ์ˆ˜
        private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
      }
      
    • DEFAULT_CONCURRENCY_LEVELย : ๋™์‹œ์— ์ž‘์—… ๊ฐ€๋Šฅํ•œ ์“ฐ๋ ˆ๋“œ ์ˆ˜
    • DEFAULT_CAPACITYย : ๋ฒ„ํ‚ท์˜ ์ˆ˜
    • ์ฆ‰,ย ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ์—์„œ ConcurrentHashMap ๊ฐ์ฒด์— ๋™์‹œ์— ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…, ์ฐธ์กฐํ•˜๋”๋ผ๋„ ๊ทธ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‹ค๋ฅธ ์„ธ๊ทธ๋จผํŠธ์— ์œ„์น˜ํ•˜๋ฉด ์„œ๋กœ ๋ฝ์„ ์–ป๊ธฐ ์œ„ํ•ดย ๊ฒฝ์Ÿํ•˜์ง€ ์•Š์Œ

์—ฐ์‚ฐ ํ™œ์šฉ ์˜ˆ์ œ

reduceValues๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋งต์˜ ์ตœ๋Œ“๊ฐ’์„ ์ฐพ๋Š” ์ฝ”๋“œ

1
2
3
ConcurrentHashMap<String, Long> map = new ConcurrentHashMap<>();
long parallelismThreshold = 1;
Optional<Integer> maxValue = Optional.ofNullable(map.reduceValues(parallelismThreshold, Long::max));
  • int, long, double ๋“ฑ์˜ ๊ธฐ๋ณธ๊ฐ’์—๋Š” ์ „์šฉ each reduce ์—ฐ์‚ฐ์ด ์ œ๊ณต๋จ โ†’ ์ด๋ฅผ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ๋ฐ•์‹ฑ ์ž‘์—…์„ ํ•  ํ•„์š”๊ฐ€ ์—†๊ณ , ํšจ์œจ์ ์œผ๋กœ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ (ex:ย reduceValuesToInt,ย reduceKeysToLong)

8.4.2. ๊ณ„์ˆ˜

  • ConcurrentHashMapย ํด๋ž˜์Šค : Map์˜ ๋งคํ•‘ ๊ฐœ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”ย mappingCountย ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•จ

    • ํ‚ค์™€ ๊ฐ’์˜ย ๋งคํ•‘์˜ย ์ˆ˜
  • ๊ธฐ์กด์˜ size ๋ฉ”์„œ๋“œ ๋Œ€์‹  ์ƒˆ ์ฝ”๋“œ์—๋Š” int๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”ย mappingCountย ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค โ†’ ๋งคํ•‘์˜ ๊ฐœ์ˆ˜๊ฐ€ int์˜ ๋ฒ”์œ„๋ฅผ ๋„˜์–ด์„œ๋Š” ์ดํ›„์˜ ์ƒํ™ฉ์„ ๋Œ€์ฒ˜ํ•  ์ˆ˜ ์žˆ์Œ

8.4.3. ์ง‘ํ•ฉ๋ทฐ

  • keySetย : ์ž๊ธฐ ์ž์‹ ์„ ์ง‘ํ•ฉ ๋ทฐ๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ƒˆ ๋ฉ”์„œ๋“œ

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    // Java code to illustrate the keys() method
    import java.util.*;
    import java.util.concurrent.*;
    
    public class ConcurrentHashMapDemo {
    	public static void main(String[] args)
    	{
    
    		// Creating an empty ConcurrentHashMap
    		ConcurrentHashMap<Integer, String> hash_map
    			= new ConcurrentHashMap<Integer, String>();
    
    		// Mapping string values to int keys
    		hash_map.put(10, "Geeks");
    		hash_map.put(15, "4");
    		hash_map.put(20, "Geeks");
    		hash_map.put(25, "Welcomes");
    		hash_map.put(30, "You");
    
    		// Displaying the HashMap
    		System.out.println("Initial Mappings are: "
    						+ hash_map);
    
    		// Using keySet() to get the set view of keys
    		System.out.println("The set is: "
    						+ hash_map.keySet());
    	}
    }
    
    1
    2
    3
    4
    
    // output
    // Initial Mappings are: {20=Geeks, 25=Welcomes, 10=Geeks, 30=You, 15=4}
    // The set is: [20, 25, 10, 30, 15]
    
    
  • Map์„ ๋ฐ”๊พธ๋ฉด ์ง‘ํ•ฉ๋„ ๋ฐ”๋€Œ๊ณ , ๋ฐ˜๋Œ€๋กœ ์ง‘ํ•ฉ์„ ๋ฐ”๊พธ๋ฉด ๋งต๋„ ์˜ํ–ฅ์„ ๋ฐ›์Œ
  • newKeySetย : ConcurrentHashMap์œผ๋กœ ์œ ์ง€๋˜๋Š” ์ง‘ํ•ฉ ๋งŒ๋“ค๊ธฐ

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
     importย java.util.Set;
     importย java.util.concurrent.*;
    
     classย ConcurrentHashMapnewKeySetExample1ย {
          publicย staticย voidย main(String[]ย args)
          {
     	 Set<String>ย hashmapย =ย ConcurrentHashMap.newKeySet();
     	 hashmap.add("AA");
     	 hashmap.add("BBB");
     	 hashmap.add("CCC");
     	 hashmap.add("DDD");
     	 System.out.println("ย Mappingsย :ย "+ย hashmap);
          }
     }
    
    // output
    //  Mappings : [AA, CCC, BBB, DDD]
    
This post is licensed under CC BY 4.0 by the author.