๐น chap8. ์ปฌ๋ ์ API ๊ฐ์
8.1 ์ปฌ๋ ์ ํฉํ ๋ฆฌ
์๋ฐ 9์์ ์์ ์ปฌ๋ ์ ๊ฐ์ฒด๋ฅผ ์ฝ๊ฒ ๋ง๋ค ์ ์๋ ๋ช ๊ฐ์ง ๋ฐฉ๋ฒ ์ ๊ณต
- ์ ์ ์์๋ฅผ ํฌํจํ๋ ๋ฆฌ์คํธ ๋ง๋ค๊ธฐ
1
2
3
4
5
// ํด๊ฐ๋ฅผ ํจ๊ป ๋ณด๋ด๋ ค๋ ์น๊ตฌ ์ด๋ฆ์ ํฌํจํ๋ ๊ทธ๋ฃน
List<String> friends = new ArrayList<>();
friends.add("Raphael");
friends.add("Olivia");
friends.add("Thibaut");
์ธ ๋ฌธ์์ด์ ์ ์ฅํ๋๋ฐ๋ ๋ง์ ์ฝ๋๊ฐ ํ์ํ๋ค.
๋ค์์ฒ๋ผ Arrays.asList() ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ฉด ์ฝ๋๋ฅผ ๊ฐ๋จํ๊ฒ ์ค์ผ ์ ์๋ค.
1
2
List<String> friends
= Arrays.asList("Raphael", "Olivia", "Thibaut");
๊ณ ์ ํฌ๊ธฐ์ ๋ฆฌ์คํธ๋ฅผ ๋ง๋ค์์ผ๋ฏ๋ก ์์๋ฅผ ๊ฐฑ์ ํ ์ ์์ง๋ง ์ ์์๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์์๋ฅผ ์ญ์ ํ ์ ์๋ค. ์์๋ฅผ ๊ฐฑ์ ํ๋ ์์ ์ ๊ด์ฐฎ์ง๋ง ์์๋ฅผ ์ถ๊ฐํ๋ ค ํ๋ฉด Unsupported OperationException์ด ๋ฐ์ํ๋ค.
1
2
3
List<String> friends = Arrays.asList("Raphael", "Olivia");
friends.set(0, "Richard");
friends.add("Thibaut");
UnsupportedOperationException ์์ธ ๋ฐ์
๋ด๋ถ์ ์ผ๋ก ๊ณ ์ ๋ ํฌ๊ธฐ์ ๋ณํํ ์ ์๋ ๋ฐฐ์ด๋ก ๊ตฌํ๋์๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ๋ค.
์งํฉ์? Arrays.asSet()์ด๋ผ๋ ํฉํ ๋ฆฌ ๋ฉ์๋๋ ์์ผ๋ฏ๋ก ๋ค๋ฅธ ๋ฐฉ๋ฒ์ด ํ์ํ๋ค. ๋ฆฌ์คํธ๋ฅผ ์ธ์๋ก ๋ฐ๋ HashSet ์์ฑ์๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
1
2
Set<String> friends
= new HashSet<>(Arrays.asList("Raphael", "Olivia", "Thibaut"));
๋๋ ๋ค์์ฒ๋ผ ์คํธ๋ฆผ API๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
1
2
3
Set<String> friends
= Stream.of("Raphael", "Olivia", "Thibaut")
.collect(Collectors.toSet());
ํ์ง๋ง ๋ ๋ฐฉ๋ฒ ๋ชจ๋ ๋ด๋ถ์ ์ผ๋ก ๋ถํ์ํ ๊ฐ์ฒด(๋ฆฌ์คํธ) ํ ๋น์ ํ์๋ก ํ๋ค. ๊ทธ๋ฆฌ๊ณ ๊ฒฐ๊ณผ๋ ๋ณํํ ์ ์๋ ์งํฉ์ด๋ผ๋ ์ฌ์ค๋ ์ฃผ๋ชฉํด์ผํ๋ค.
8.1.1 ๋ฆฌ์คํธ ํฉํ ๋ฆฌ
List.of ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ์ด์ฉํด ๊ฐ๋จํ๊ฒ ๋ฆฌ์คํธ๋ฅผ ๋ง๋ค ์ ์๋ค.
1
2
List<String> friends = List.of("Raphael", "Olivia", "Thibaut");
System.out.println(friends);
์ ์ฝ๋์์ friends ๋ฆฌ์คํธ์ ์์๋ฅผ ์ถ๊ฐํด๋ณด์.
1
2
List<String> friends = List.of("Raphael", "Olivia", "Thibaut");
friends.add("Chih-Chun");
์ ์ฝ๋๋ฅผ ์คํํ๋ฉด java.lang.UnsupportedOperationException์ด ๋ฐ์ํ๋ค. ๋ณ๊ฒฝํ ์ ์๋ ๋ฆฌ์คํธ๊ฐ ๋ง๋ค์ด์ก๊ธฐ ๋๋ฌธ์ด๋ค.
set() ๋ฉ์๋๋ก ์์ดํ ์ ๋ฐ๊พธ๋ คํด๋ ๋น์ทํ ์์ธ๊ฐ ๋ฐ์ํ๋ค. ๋ฐ๋ผ์ set ๋ฉ์๋๋ก๋ ๋ฆฌ์คํธ๋ฅผ ๋ฐ๊ฟ ์ ์๋ค.
ํ์ง๋ง ์ด๋ฐ ์ ์ฝ์ ๊ผญ ๋์๊ฒ๋ง์ ์๋๋ค. ์ปฌ๋ ์ ์ด ์๋์น ์๊ฒ ๋ณํ๋ ๊ฒ์ ๋ง์ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฆฌ์คํธ๋ฅผ ๋ฐ๊ฟ์ผ ํ๋ ์ํฉ์ด๋ผ๋ฉด ์ง์ ๋ฆฌ์คํธ๋ฅผ ๋ง๋ค๋ฉด ๋๋ค. ๋ง์ง๋ง์ผ๋ก null ์์๋ ๊ธ์งํ๋ฏ๋ก ์๋์น ์์ ๋ฒ๊ทธ๋ฅผ ๋ฐฉ์งํ๊ณ ์กฐ๊ธ ๋ ๊ฐ๊ฒฐํ ๋ด๋ถ ๊ตฌํ์ ๋ฌ์ฑํ๋ค.
๋ฆฌ์คํธ ๋ง๋๋ ๋ฐฉ๋ฒ
ํฉํ ๋ฆฌ ๋ฉ์๋
๋ฐ์ดํฐ ์ฒ๋ฆฌ ํ์์ ์ค์ ํ๊ฑฐ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณํํ ํ์๊ฐ ์๋ค๋ฉด ์ฌ์ฉ
ํฉํ ๋ฆฌ ๋ฉ์๋ ๊ตฌํ์ด ๋ ๋จ์ํ๊ณ ๋ชฉ์ ์ ๋ฌ์ฑํ๋๋ฐ ์ถฉ๋ถํ๊ธฐ ๋๋ฌธ
์คํธ๋ฆผ API
Collectors.toList() ๋ฑ์ ์ปฌ๋ ํฐ๋ก ์คํธ๋ฆผ์ ๋ฆฌ์คํธ๋ก ๋ณํ ๊ฐ๋ฅ
๋ฐ์ดํฐ๋ฅผ ๋ณํํ ํ์๊ฐ ์๋ค๋ฉด ์ฌ์ฉ
8.1.2 ์งํฉ ํฉํ ๋ฆฌ
List.of์ ๋น์ทํ ๋ฐฉ๋ฒ์ผ๋ก ๋ฐ๊ฟ ์ ์๋ ์งํฉ์ ๋ง๋ค ์ ์๋ค.
1
2
Set<String> friends = Set.of("Raphael", "Olivia", "Thibaut");
System.out.println(friends);
์ค๋ณต๋๋ ์์๋ฅผ ์ ๊ณตํด ์งํฉ์ ๋ง๋ค๋ ค๊ณ ํ๋ฉด Olivia๋ผ๋ ์์๊ฐ ์ค๋ณต๋์ด ์๋ค๋ ์ค๋ช ๊ณผ ํจ๊ป IllegalArgumentException์ด ๋ฐ์ํ๋ค.
1
Set<String> friends = Set.of("Raphael", "Olivia", "Olivia");
8.1.3 ๋งต ํฉํ ๋ฆฌ
์๋ฐ 9์์๋ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ๋ฐ๊ฟ ์ ์๋ ๋งต์ ์ด๊ธฐํํ ์ ์๋ค.
Map.of
Map.of ํฉํ ๋ฆฌ ๋ฉ์๋์ ํค์ ๊ฐ์ ๋ฒ๊ฐ์ ์ ๊ณตํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๋งต์ ๋ง๋ค ์ ์๋ค.
1
2
3
Map<String, Integer> ageOfFriends
= Map.of("Raphael", 30, "Olivia", 25, "Thibaut", 26);
System.out.println(ageOfFriends);
์ด ๊ฐ ์ดํ์ ํค์ ์์ ๊ฐ์ง ์์ ๋งต์ ๋ง๋ค ๋๋ ์ด ๋ฉ์๋๊ฐ ์ ์ฉํ๋ค.
Map.ofEntries
๊ทธ ์ด์์ ๋งต์์๋ 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("Raphael", 30),
entry("Olivia", 25),
entry("Thibaut", 26));
System.out.println(ageOfFriends);
Map.entry๋ Map.Entry ๊ฐ์ฒด๋ฅผ ๋ง๋๋ ์๋ก์ด ํฉํ ๋ฆฌ ๋ฉ์๋์ด๋ค.
Quiz. ๋ค์ ์ฝ๋๋ฅผ ์คํํ ๊ฒฐ๊ณผ๋?
1 2 3
List<String> actors = List.of("Keanu", "Jessica"); actors.set(0, "Brad"); System.out.println(actors);
์ ๋ต
UnsupportedOperationException์ด ๋ฐ์ํ๋ค. List.of๋ก ๋ง๋ ์ปฌ๋ ์ ์ ๋ฐ๊ฟ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
8.2 ๋ฆฌ์คํธ์ ์งํฉ ์ฒ๋ฆฌ
์๋ฐ 8์์๋ List, Set ์ธํฐํ์ด์ค์ ๋ค์๊ณผ ๊ฐ์ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๋ค.
removeIf
: ํ๋ ๋์ผ์ดํธ๋ฅผ ๋ง์กฑํ๋ ์์๋ฅผ ์ ๊ฑฐํ๋ค. List๋ Set์ ๊ตฌํํ๊ฑฐ๋ ๊ทธ ๊ตฌํ์ ์์๋ฐ์ ๋ชจ๋ ํด๋์ค์ ์ด์ฉํ ์ ์๋ค.
replaceAll
: ๋ฆฌ์คํธ์์ ์ด์ฉํ ์ ์๋ ๊ธฐ๋ฅ์ผ๋ก UnaryOperator ํจ์๋ฅผ ์ด์ฉํด ์์๋ฅผ ๋ฐ๊พผ๋ค.
sort
: List ์ธํฐํ์ด์ค์์ ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ผ๋ก ๋ฆฌ์คํธ๋ฅผ ์ ๋ ฌํ๋ค.
์ด๋ค ๋ฉ์๋๋ ํธ์ถํ ์ปฌ๋ ์ ์์ฒด๋ฅผ ๋ฐ๊พผ๋ค. ์๋ก์ด ๊ฒฐ๊ณผ๋ฅผ ๋ง๋๋ ์คํธ๋ฆผ ๋์๊ณผ ๋ฌ๋ฆฌ ์ด๋ค ๋ฉ์๋๋ ๊ธฐ์กด ์ปฌ๋ ์ ์ ๋ฐ๊พผ๋ค.
์ ์ด๋ฐ ๋ฉ์๋๊ฐ ์ถ๊ฐ๋์์๊น? ์ปฌ๋ ์ ์ ๋ฐ๊พธ๋ ๋์์ ์๋ฌ๋ฅผ ์ ๋ฐํ๋ฉฐ ๋ณต์กํจ์ ๋ํ๋ค.
8.2.1 removeIf ๋ฉ์๋
๋ค์์ ์ซ์๋ก ์์๋๋ ์ฐธ์กฐ ์ฝ๋๋ฅผ ๊ฐ์ง ํธ๋์ญ์ ์ ์ญ์ ํ๋ ์ฝ๋๋ค.
1
2
3
4
5
for (Transaction transaction : transactions) {
if (Character.isDigit(transaction.getReferenceCode().charAt(0))) {
transactions.remove(transaction);
}
}
์ ์ฝ๋๋ ConcurrentModificationException์ ์ผ์ผํจ๋ค. ๋ด๋ถ์ ์ผ๋ก for-each ๋ฃจํ๋ 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 ๊ฐ์ฒด, next(), hasNext()๋ฅผ ์ด์ฉํด ์์ค๋ฅผ ์ง์ํ๋ค.
- 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.move();**
}
}
์ฝ๋๊ฐ ์กฐ๊ธ ๋ณต์กํด์ก๋ค. ์ด ์ฝ๋ ํจํด์ ์๋ฐ 8์ removeIf ๋ฉ์๋๋ก ๋ฐ๊ฟ ์ ์๋ค. ๊ทธ๋ฌ๋ฉด ์ฝ๋๊ฐ ๋จ์ํด์ง ๋ฟ ์๋๋ผ ๋ฒ๊ทธ๋ ์๋ฐฉํ ์ ์๋ค. removeIf ๋ฉ์๋๋ ์ญ์ ํ ์์๋ฅผ ๊ฐ๋ฆฌํค๋ ํ๋ ๋์ผ์ดํธ๋ฅผ ์ธ์๋ก ๋ฐ๋๋ค.
1
2
transactions.removeIf(transaction ->
Character.isDigit(transaction.getReferenceCode().charAt(0)));
8.2.2 replaceAll ๋ฉ์๋
List ์ธํฐํ์ด์ค์ replaceAll ๋ฉ์๋๋ฅผ ์ด์ฉํด ๋ฆฌ์คํธ์ ๊ฐ ์์๋ฅผ ์๋ก์ด ์์๋ก ๋ฐ๊ฟ ์ ์๋ค. ์คํธ๋ฆผ API๋ฅผ ์ฌ์ฉํ๋ฉด ๋ค์์ฒ๋ผ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์๋ค.
1
2
3
4
5
referenceCodes.stream()
.map(code -> Character.toUpperCase(code.charAt(0))
+ code.subString(1))
.collect(Collectors.toList())
.forEach(System.out::println);
ํ์ง๋ง ์ด ์ฝ๋๋ ์ ๋ฌธ์์ด ์ปฌ๋ ์ ์ ๋ง๋ ๋ค. ๊ธฐ์กด์ ์ปฌ๋ ์ ์ ๋ฐ๊พธ๊ธฐ ์ํด์ ๋ค์์ฒ๋ผ ListIterator ๊ฐ์ฒด (์์๋ฅผ ๋ฐ๊พธ๋ set() ๋ฉ์๋ ์ง์)๋ฅผ ์ด์ฉํ ์ ์๋ค.
1
2
3
4
for (ListIterator<String> iterator = referenceCodes.listIterator(); iterator.hasNext(); ) {
String code = iterator.next();
iterator.set(Character.toUpperCase(code.charAt(0)) + code.substring(1));
}
์ฝ๋๊ฐ ์กฐ๊ธ ๋ณต์กํด์ก๋ค. ์ปฌ๋ ์ ์์ฒด๋ฅผ Iterator ๊ฐ์ฒด์ ํผ์ฉํ๋ฉด ๋ฐ๋ณต๊ณผ ์ปฌ๋ ์ ๋ฐ๋ณต์ด ๋์์ ์ด๋ฃจ์ด์ง๋ฉด์ ์ฝ๊ฒ ๋ฌธ์ ๋ฅผ ์ผ์ผํจ๋ค. ์๋ฐ 8์ ๊ธฐ๋ฅ์ ์ด์ฉํ๋ฉด ๋ค์์ฒ๋ผ ๊ฐ๋จํ๊ฒ ๊ตฌํํ ์ ์๋ค.
1
2
referenceCodes.replaceAll(code -> Character.toUpperCase(code.charAt(0))
+ code.substring(1));
8.3 ๋งต ์ฒ๋ฆฌ
์๋ฐ 8์์๋ Map ์ธํฐํ์ด์ค์ ๋ช ๊ฐ์ง ๋ํดํธ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๋ค. ์์ฃผ ์ฌ์ฉ๋๋ ํจํด์ ๊ฐ๋ฐ์๊ฐ ์ง์ ๊ตฌํํ ํ์๊ฐ ์๋๋ก ์ด๋ค ๋ฉ์๋๋ฅผ ์ถ๊ฐํ ๊ฒ์ด๋ค.
8.3.1 forEach ๋ฉ์๋
๋งต์์ ํค์ ๊ฐ์ ๋ฐ๋ณตํ๋ฉฐ ํ์ธํ๋ ์์ ์ ๋งค์ฐ ๊ท์ฐฎ๋ค. ์ค์ ๋ก๋ Map.Entry<K, V>์ ๋ฐ๋ณต์๋ฅผ ์ด์ฉํด ๋งต์ ํญ๋ชฉ ์งํฉ์ ๋ฐ๋ณตํ ์ ์๋ค.
1
2
3
4
5
for (Map.Entry<String, Integer> entry: ageOfFriends.entrySet()) {
String friend = entry.getKey();
Integer age = entry.getValue();
System.out.println(friend + " is " + age + " years old");
}
์๋ฐ 8๋ถํฐ Map ์ธํฐํ์ด์ค๋ BiConsumer(ํค์ ๊ฐ์ ์ธ์๋ก๋ฐ์)๋ฅผ ์ธ์๋ก ๋ฐ์ forEach ๋ฉ์๋๋ฅผ ์ง์ํ๋ฏ๋ก ์ฝ๋๋ฅผ ์กฐ๊ธ ๋ ๊ฐ๋จํ๊ฒ ๊ตฌํํ ์ ์๋ค.
1
2
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
9
Map<String, String> favoriteMovies
= Map.ofEntries(
entry("Raphael", "Star Wars"),
entry("Cristina", "Matrix"),
entry("Olivia", "James Bond"));
favoriteMovies.entrySet().stream()
.sorted(Entry.comparingByKey())
.forEachOrdered(System.out::println); // ์ฌ๋์ ์ด๋ฆ์ ์ํ๋ฒณ ์์ผ๋ก ์คํธ๋ฆผ ์์ ์ฒ๋ฆฌ
๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ๋ค.
1
2
3
Cristina=Matrix
Olivia=James Bond
Raphael=Star Wars
8.3.3 getOrDefault ๋ฉ์๋
๊ธฐ์กด์๋ ์ฐพ์ผ๋ ค๋ ํค๊ฐ ์กด์ฌํ์ง ์์ผ๋ฉด null์ด ๋ฐํ๋๋ฏ๋ก NullPointerException์ ๋ฐฉ์งํ๋ ค๋ฉด ์์ฒญ ๊ฒฐ๊ณผ๊ฐ null์ธ์ง ํ์ธํด์ผ ํ๋ค. ๊ธฐ๋ณธ๊ฐ์ ๋ฐํํ๋ ๋ฐฉ์์ผ๋ก ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค.
getOrDefault ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ฉด ์ฝ๊ฒ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค.
- ์ฒซ ๋ฒ์งธ ์ธ์ : ํค
- ๋ ๋ฒ์งธ ์ธ์ : ๊ธฐ๋ณธ๊ฐ
๋งต์ ํค๊ฐ ์กด์ฌํ์ง ์์ผ๋ฉด ๋ ๋ฒ์งธ ์ธ์๋ก ๋ฐ์ ๊ธฐ๋ณธ๊ฐ์ ๋ฐํํ๋ค.
1
2
3
4
5
6
Map<String, String> favoriteMovies
= Map.ofEntries(
entry("Raphael", "Star Wars"),
entry("Olivia", "James Bond"));
System.out.println(favoriteMovies.getOrDefault("Olivia", "Matrix")); //James Bond ์ถ๋ ฅ
System.out.println(favoriteMovies.getOrDefault("Thibaut", "Matrix")); // Matrix ์ถ๋ ฅ
ํค๊ฐ ์กด์ฌํ๋๋ผ๋ ๊ฐ์ด null์ธ ์ํฉ์์ getOrDefault๊ฐ null์ ๋ฐํํ ์ ์๋ค. โ ํค๊ฐ ์กด์ฌํ๋๋์ ์ฌ๋ถ์ ๋ฐ๋ผ ๋ ๋ฒ์จฐ ์ธ์๊ฐ ๋ฐํ๋ ์ง ๊ฒฐ์ ๋๋ค.
8.3.4 ๊ณ์ฐ ํจํด
๋งต์ ํค๊ฐ ์กด์ฌํ๋์ง ์ฌ๋ถ์ ๋ฐ๋ผ ์ด๋ค ๋์์ ์คํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํด์ผํ๋ ์ํฉ์ด ํ์ํ ๋๊ฐ ์๋ค. ๋ค์ ์ธ ๊ฐ์ง ์ฐ์ฐ์ ์ ๊ณตํ๋ค.
computeIfAbsent
: ์ ๊ณต๋ ํค์ ํด๋นํ๋ ๊ฐ์ด ์์ผ๋ฉด(๊ฐ์ด ์๊ฑฐ๋ ๋), ํค๋ฅผ ์ด์ฉํด ์ ๊ฐ์ ๊ณ์ฐํ๊ณ ๋งต์ ์ถ๊ฐํ๋ค.
computeIfPresent
: ์ ๊ณต๋ ํค๊ฐ ์กด์ฌํ๋ฉด ์ ๊ฐ์ ๊ณ์ฐํ๊ณ ๋งต์ ์ถ๊ฐํ๋ค.
compute
: ์ ๊ณต๋ ํค๋ก ์ ๊ฐ์ ๊ณ์ฐํ๊ณ ๋งต์ ์ ์ฅํ๋ค.
์ ๋ณด๋ฅผ ์บ์ํ ๋ computeIfAbsent๋ฅผ ํ์ฉํ ์ ์๋ค. ํ์ผ ์งํฉ์ ๊ฐ ํ์ ํ์ฑํด SHA-256์ ๊ณ์ฐํ๋ค๊ณ ๊ฐ์ ํ ๋, ๊ธฐ์กด์ ์ด๋ฏธ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ค๋ฉด ์ด ๊ฐ์ ๋ค์ ๊ณ์ฐํ ํ์๊ฐ ์๋ค.
๋งต์ ์ด์ฉํด ์บ์๋ฅผ ๊ตฌํํ๋ค๊ณ ๊ฐ์ ํ๋ฉด ๋ค์์ฒ๋ผ MessageDigest ์ธ์คํด์ค๋ก SHA-256 ํด์๋ฅผ ๊ณ์ฐํ ์ ์๋ค.
1
2
Map<String, byte[]> dataToHash = new HashMap<>();
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
์ด์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋ณตํ๋ฉด์ ๊ฒฐ๊ณผ๋ฅผ ์บ์ํ๋ค.
1
2
3
4
5
6
7
lines.forEach(line ->
dataToHash.computeIfAbsent(line, this::calculateDigest));
// line - ๋งต์์ ์ฐพ์ ํค, this::calculateDigest - ํค๊ฐ ์กด์ฌํ์ง ์์ผ๋ฉด ๋์ ์คํ
private byte[] calculateDigest(String key) { // ํฌํผ๊ฐ ์ ๊ณต๋ ํค์ ํด์๋ฅผ ๊ณ์ฐ
return messageDigest.digest(key.getBytes(StandardCharsets.UTF_8));
}
์ฌ๋ฌ ๊ฐ์ ์ ์ฅํ๋ ๋งต ์ฒ๋ฆฌ์๋ ์ด ํจํด์ ์ ์ฉํ๊ฒ ํ์ฉํ ์ ์๋ค.
Map<K, List
1
2
3
4
5
6
7
8
9
10
// Raphael์๊ฒ ์ค ์ํ ๋ชฉ๋ก ๋ง๋ค๊ธฐ
String friend = "Raphael";
List<String> movies = friendsToMovies.get(friend);
if (movies == null) { // ๋ฆฌ์คํธ๊ฐ ์ด๊ธฐํ๋์๋์ง ํ์ธ
movies = new ArrayList<>();
friendsToMovies.put(friend, movies);
}
movies.add("Star Wars"); //์ํ๋ฅผ ์ถ๊ฐ
System.out.println(friendsToMovies); // {Raphael: [Star Wars]}
computeIfAbsent๋ ํค๊ฐ ์กด์ฌํ์ง ์์ผ๋ฉด ๊ฐ์ ๊ณ์ฐํด ๋งต์ ์ถ๊ฐํ๊ณ ํค๊ฐ ์กด์ฌํ๋ฉด ๊ธฐ์กด ๊ฐ์ ๋ฐํํ๋ค.
1
2
friendsToMovies.computeIfAbsent("Raphael", name -> new ArrayList<>())
.add("Star Wars"); //{Raphael: [Star Wars]}
8.3.5 ์ญ์ ํจํด
์๋ฐ 8์์๋ ํน์ ํ ๊ฐ๊ณผ ์ฐ๊ด๋์์ ๋๋ง ํญ๋ชฉ์ ์ ๊ฑฐํ๋ remove ์ค๋ฒ๋ก๋ ๋ฒ์ ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค.
๊ธฐ์กด์๋ ๋ค์๊ณผ ๊ฐ์ด ์ฝ๋๋ฅผ ๊ตฌํํ๋ค.
1
2
3
4
5
6
7
8
9
10
String key = "Raphael";
String value = "Jack Reacher 2";
if (favoriteMovies.containsKey(key) &&
Objects.equals(favoriteMovies.get(key), value)) {
favoriteMovies.remove(key);
return true;
}
else {
return false;
}
์๋ฐ 8 ์ดํ๋ก๋ ๋ค์์ฒ๋ผ ์ฝ๋๋ฅผ ๊ฐ๊ฒฐํ๊ฒ ๊ตฌํํ ์ ์๋ค.
1
favoriteMovies.remove(key, value);
8.3.6 ๊ต์ฒด ํจํด
๋งต์ ํญ๋ชฉ์ ๋ฐ๊พธ๋ ๋ฐ ์ฌ์ฉํ ์ ์๋ ๋ ๊ฐ์ ๋ฉ์๋๊ฐ ๋งต์ ์ถ๊ฐ๋์๋ค.
replaceAll
: BiFunction์ ์ ์ฉํ ๊ฒฐ๊ณผ๋ก ๊ฐ ํญ๋ชฉ์ ๊ฐ์ ๊ต์ฒดํ๋ค. ์ด ๋ฉ์๋๋ ์ด์ ์ ์ดํด๋ณธ List์ replaceAll๊ณผ ๋น์ทํ ๋์์ ์ํํ๋ค.
Replace
: ํค๊ฐ ์กด์ฌํ๋ฉด ๋งต์ ๊ฐ์ ๋ฐ๊พผ๋ค. ํค๊ฐ ํน์ ๊ฐ์ผ๋ก ๋งคํ๋์์ ๋๋ง ๊ฐ์ ๊ต์ฒดํ๋ ์ค๋ฒ๋ก๋ ๋ฒ์ ๋ ์๋ค.
๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ๋งต์ ๋ชจ๋ ๊ฐ์ ํ์์ ๋ฐ๊ฟ ์ ์๋ค.
1
2
3
4
5
6
// replaceAll์ ์ ์ฉํ ๊ฒ์ด๋ฏ๋ก ๋ฐ๊ฟ ์ ์๋ ๋งต์ ์ฌ์ฉํด์ผ ํ๋ค.
Map<String, String> favoriteMovies = new HashMap<>();
favoriteMovies.put("Raphael", "Star Wars");
favoriteMovies.put("Olivia", "james bond");
favoriteMovies.replaceAll((friend, movie) -> movie.toUpperCase());
System.out.println(favoriteMovies); // {Olivia=JAMES BOND, Raphael=STAR WARS}
์ง๊ธ๊น์ง ๋ฐฐ์ด replace ํจํด์ ํ ๊ฐ์ ๋งต์๋ง ์ ์ฉํ ์ ์๋ค. ๋ ๊ฐ์ ๋งต์์ ๊ฐ์ ํฉ์น๊ฑฐ๋ ๋ฐ๊ฟ์ผ ํ๋ค๋ฉด merge ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ํด๊ฒฐํ๋ค.
8.3.7 ํฉ์นจ
๋ ๊ทธ๋ฃน์ ์ฐ๋ฝ์ฒ๋ฅผ ํฌํจํ๋ ๋ ๊ฐ์ ๋งต์ ํฉ์น๋ค๊ณ ๊ฐ์ ํ์. ๋ค์์ฒ๋ผ putAll์ ์ฌ์ฉํ ์ ์๋ค.
1
2
3
4
5
6
7
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); // friends์ ๋ชจ๋ ํญ๋ชฉ์ everyone์ผ๋ก ๋ณต์ฌ
์ค๋ณต๋ ํค๊ฐ ์๋ค๋ฉด ์ ์ฝ๋๋ ์ ์๋ํ๋ค.
๊ฐ์ ์ข ๋ ์ ์ฐํ๊ฒ ํฉ์ณ์ผ ํ๋ค๋ฉด ์๋ก์ด merge ๋ฉ์๋๋ฅผ ์ด์ฉํ ์ ์๋ค. ์ด ๋ฉ์๋๋ ์ค๋ณต๋ ํค๋ฅผ ์ด๋ป๊ฒ ํฉ์น ์ง ๊ฒฐ์ ํ๋ BiFunction์ ์ธ์๋ก ๋ฐ๋๋ค.
family์ friends ๋ ๋งต ๋ชจ๋์ Cristina๊ฐ ๋ค๋ฅธ ์ํ ๊ฐ์ผ๋ก ์กด์ฌํ๋ค๊ณ ๊ฐ์ ํ์.
1
2
3
4
5
6
Map<String, String> family = Map.ofEntries(
entry("Teo", "Star Wars"),
entry("Cristina", "James Bond"));
Map<String, String> friends = Map.ofEntries(
entry("Raphael", "Star Wars"),
entry("Cristina", "Matrix"));
forEach์ merge ๋ฉ์๋๋ฅผ ์ด์ฉํด ์ถฉ๋์ ํด๊ฒฐํ ์ ์๋ค. ๋ค์ ์ฝ๋๋ ๋ ์ํ์ ๋ฌธ์์ด์ ํฉ์น๋ ๋ฐฉ๋ฒ์ผ๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ค.
1
2
3
4
5
6
7
8
Map<String, String> everyone = new HashMap<>(family);
friends.forEach((k, v) ->
// ์ค๋ณต๋ ํค๊ฐ ์์ผ๋ฉด ๋ ๊ฐ์ ์ฐ๊ฒฐ
everyone.merge(k, v, (movie1, movie2) -> movie1 + " & " + movie2));
System.out.println(everyone);
// ๊ฒฐ๊ณผ
// Outputs {Raphael=Star Wars, Cristina=James Bond & Matrix, Teo=Star Wars}
์๋ฐ๋ ์์ ์ค๋ช ํ๋ ๊ฒ์ฒ๋ผ merge ๋ฉ์๋๋ null๊ฐ๊ณผ ๊ด๋ จ๋ ๋ณต์กํ ์ํฉ๋ ์ฒ๋ฆฌํ๋ค.
merge๋ฅผ ์ด์ฉํด ์ด๊ธฐํ ๊ฒ์ฌ๋ฅผ ๊ตฌํํ ์๋ ์๋ค.
์ํ๋ฅผ ๋ช ํ ์์ฒญํ๋์ง ๊ธฐ๋กํ๋ ๋งต์ด ์๋ค๊ณ ๊ฐ์ ํ์. ํด๋น ๊ฐ์ ์ฆ๊ฐ์ํค๊ธฐ ์ ์ ๊ด๋ จ ์ํ๊ฐ ์ด๋ฏธ ๋งต์ ์กด์ฌํ๋์ง ํ์ธํด์ผ ํ๋ค.
1
2
3
4
5
6
7
8
9
Map<String, Long> moviesToCount = new HashMap<>();
String movieName = "JamesBond";
long count = moviesToCount.get(movieName);
if (count == null) {
moviesToCount.put(movieName, 1);
}
else {
moviesToCount.put(movieName, count + 1);
}
์ ์ฝ๋๋ฅผ ๋ค์์ฒ๋ผ ๊ตฌํํ ์ ์๋ค.
1
moviesToCount.merge(movieName, 1L, (key, count) -> count + 1L);
์ ์ฝ๋์์ merge์ ๋ ๋ฒ์งธ ์ธ์๋ 1L์ด๋ค. ์๋ฐ๋ ์ ๋ฐ๋ฅด๋ฉด ์ด ์ธ์๋ โํค์ ์ฐ๊ด๋ ๊ธฐ์กด ๊ฐ์ ํฉ์ณ์ง ๋์ด ์๋ ๊ฐ ๋๋ ๊ฐ์ด ์๊ฑฐ๋ ํค์ ๋ ๊ฐ์ด ์ฐ๊ด๋์ด ์๋ค๋ฉด ์ด ๊ฐ์ ํค์ ์ฐ๊ฒฐโํ๋๋ฐ ์ฌ์ฉ๋๋ค.
ํค์ ๋ฐํ๊ฐ์ด ๋์ด๋ฏ๋ก ์ฒ์์๋ 1์ด ์ฌ์ฉ๋๋ค. ๊ทธ ๋ค์๋ถํฐ๋ ๊ฐ์ด 1๋ก ์ด๊ธฐํ๋์ด ์์ผ๋ฏ๋ก BiFunction์ ์ ์ฉํด ๊ฐ์ด ์ฆ๊ฐ๋๋ค.
Quiz. ๋ค์ ์ฝ๋๊ฐ ์ด๋ค ์์ ์ ์ํํ๋์ง ํ์ ํ ๋ค์ ์ฝ๋๋ฅผ ๋จ์ํํ ์ ์๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํ์์ค.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Map<String, Integer> movies = new HashMap<>(); movies.put("JamesBond", 20); movies.put("Matrix", 15); movies.put("Harry Potter", 5); Iterator<Map.Entry<String, Integer>> iterator = movies.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, Integer> entry = iterator.next(); if (entry.getValue() < 10) { iterator.remove(); } } System.out.println(movies); //{Matrix=15, JamesBond=20}
์ ๋ต
๋งต์ ํญ๋ชฉ ์งํฉ์ ํ๋ ๋์ผ์ดํธ๋ฅผ ์ธ์๋ก ๋ฐ์ ํญ๋ชฉ์ ์ญ์ ํ๋ removeIf ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
1
movies.entrySet().removeIf(entry -> entry.getValue() < 10);
8.4 ๊ฐ์ ๋ ConcurrentHashMap
ConcurrentHashMap ํด๋์ค๋ ๋์์ฑ ์นํ์ ์ด๋ฉฐ ์ต์ ๊ธฐ์ ์ ๋ฐ์ํ HashMap ๋ฒ์ ์ด๋ค.
ConcurrentHashMap์ ๋ด๋ถ ์๋ฃ๊ตฌ์กฐ์ ํน์ ๋ถ๋ถ๋ง ์ ๊ถ ๋์ ์ถ๊ฐ, ๊ฐฑ์ ์์ ์ ํ์ฉํ๋ค. ๋ฐ๋ผ์ ๋๊ธฐํ๋ Hashtable ๋ฒ์ ์ ๋นํด ์ฝ๊ธฐ ์ฐ๊ธฐ ์ฐ์ฐ ์ฑ๋ฅ์ด ์๋ฑํ๋ค.(์ฐธ๊ณ ๋ก, ํ์ค HashMap์ ๋น๋๊ธฐ๋ก ๋์ํจ)
8.4.1 ๋ฆฌ๋์ค์ ๊ฒ์
ConcurrentHashMap์ ์คํธ๋ฆผ์์ ๋ดค๋ ๊ฒ๊ณผ ๋น์ทํ ์ข ๋ฅ์ ์ธ ๊ฐ์ง ์๋ก์ด ์ฐ์ฐ์ ์ง์ํ๋ค.
forEach
: ๊ฐ (ํค, ๊ฐ) ์์ ์ฃผ์ด์ง ์ก์ ์ ์คํ
reduce
: ๋ชจ๋ (ํค, ๊ฐ) ์์ ์ ๊ณต๋ ๋ฆฌ๋์ค ํจ์๋ฅผ ์ด์ฉํด ๊ฒฐ๊ณผ๋ก ํฉ์นจ
search
: ๋์ด ์๋ ๊ฐ์ ๋ฐํํ ๋๊น์ง ๊ฐ (ํค, ๊ฐ) ์์ ํจ์๋ฅผ ์ ์ฉ
๋ค์์ฒ๋ผ ํค์ ํจ์ ๋ฐ๊ธฐ, ๊ฐ, Map.Entry, (ํค, ๊ฐ) ์ธ์๋ฅผ ์ด์ฉํ ๋ค ๊ฐ์ง ์ฐ์ฐ์ ์ง์ํ๋ค.
- ํค, ๊ฐ์ผ๋ก ์ฐ์ฐ(forEach, reduce, search)
- ํค๋ก ์ฐ์ฐ(forEachKey, reduceKeys, searchKeys)
- ๊ฐ์ผ๋ก ์ฐ์ฐ(forEachValue, reduceValues, searchValues)
- Map.Entry ๊ฐ์ฒด๋ก ์ฐ์ฐ(forEachEntry, reduceEntries, searchEntries)
์ด๋ค ์ฐ์ฐ์ ConcurrentHashMap์ ์ํ๋ฅผ ์ ๊ทธ์ง ์๊ณ ์ฐ์ฐ์ ์ํํ๋ค๋ ์ ์ ์ฃผ๋ชฉํด์ผํ๋ค. ๋ฐ๋ผ์ ์ด๋ค ์ฐ์ฐ์ ์ ๊ณตํ ํจ์๋ ๊ณ์ฐ์ด ์งํ๋๋ ๋์ ๋ฐ๋ ์ ์๋ ๊ฐ์ฒด, ๊ฐ, ์์ ๋ฑ์ ์์กดํ์ง ์์์ผ ํ๋ค.
๋ํ ์ด๋ค ์ฐ์ฐ์ ๋ณ๋ ฌ์ฑ ๊ธฐ์ค๊ฐ์ ์ง์ ํด์ผ ํ๋ค. ๋งต์ ํฌ๊ธฐ๊ฐ ์ฃผ์ด์ง ๊ธฐ์ค๊ฐ๋ณด๋ค ์์ผ๋ฉด ์์ฐจ์ ์ผ๋ก ์ฐ์ฐ์ ์คํํ๋ค. ๊ธฐ์ค๊ฐ์ 1๋ก ์ง์ ํ๋ฉด ๊ณตํต ์ค๋ ๋ ํ์ ์ด์ฉํด ๋ณ๋ ฌ์ฑ์ ๊ทน๋ํํ๋ค.
Long.MAX_VALUE๋ฅผ ๊ธฐ์ค๊ฐ์ผ๋ก ์ค์ ํ๋ฉด ํ ๊ฐ์ ์ค๋ ๋๋ก ์ฐ์ฐ์ ์คํํ๋ค. ์ํํธ์จ์ด ์ํคํ ์ฒ๊ฐ ๊ณ ๊ธ ์์ค์ ์์ ํ์ฉ ์ต์ ํ๋ฅผ ์ฌ์ฉํ๊ณ ์์ง ์๋ค๋ฉด ๊ธฐ์ค๊ฐ ๊ท์น์ ๋ฐ๋ฅด๋ ๊ฒ์ด ์ข๋ค.
์ด ์์ ์์๋ reduceValues ๋ฉ์๋๋ฅผ ์ด์ฉํด ๋งต์ ์ต๋๊ฐ์ ์ฐพ๋๋ค.
1
2
3
4
5
// ์ฌ๋ฌ ํค์ ๊ฐ์ ํฌํจํ๋๋ก ๊ฐฑ์ ๋ ConcurrentHashMap
ConcurrentHashMap<String, Long> map = new ConcurrentHashMap<>();
long parallelismThreshold = 1;
Optional<Integer> maxValue =
Optional.ofNullable(map.reduceValues(parallelismThreshold, Long::max));
int, long, double ๋ฑ์ ๊ธฐ๋ณธ๊ฐ์๋ ์ ์ฉ each reduce ์ฐ์ฐ์ด ์ ๊ณต๋๋ฏ๋ก reduceValuesToInt, reduceKeysToLong ๋ฑ์ ์ด์ฉํ๋ฉด ๋ฐ์ฑ์์ ์ ํ ํ์๊ฐ ์๊ณ ํจ์จ์ ์ผ๋ก ์์ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ค.
8.4.2 ๊ณ์
ConcurrentHashMap ํด๋์ค๋ ๋งต์ ๋งคํ ๊ฐ์๋ฅผ ๋ฐํํ๋ mappingCount ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค. ๊ธฐ์กด์ size ๋ฉ์๋ ๋์ ์ ์ฝ๋์์ int๋ฅผ ๋ฐํํ๋ mappingCount ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
โ int์ ๋ฒ์๋ฅผ ๋์ด์๋ ์ดํ์ ์ํฉ์ ๋์ฒํ ์ ์๊ธฐ ๋๋ฌธ
8.4.3 ์งํฉ๋ทฐ
ConcurrentHashMap ํด๋์ค๋ ConcurrentHashMap์ ์งํฉ ๋ทฐ๋ก ๋ฐํํ๋ keySet์ด๋ผ๋ ์ ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค. ๋งต์ ๋ฐ๊พธ๋ฉด ์งํฉ๋ ๋ฐ๋๊ณ ๋ฐ๋๋ก ์งํฉ์ ๋ฐ๊พธ๋ฉด ๋งต๋ ์ํฅ์ ๋ฐ๋๋ค. newKeySet์ด๋ผ๋ ์ ๋ฉ์๋๋ฅผ ์ด์ฉํด ConcurrentHashMap์ผ๋ก ์ ์ง๋๋ ์งํฉ๋ ๋ง๋ค ์ ์๋ค.