CHAP21 - Modern-Java-in-Action/Online-Study GitHub Wiki

์ด ์žฅ์˜ ๋‚ด์šฉ

  • ์ž๋ฐ” 8์˜ ๊ธฐ๋Šฅ๊ณผ ์ž๋ฐ” 8์ด ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํ˜•์‹์— ๊ฐ€์ ธ์˜ฌ ๋ณ€ํ™”
  • ์ƒˆ๋กœ์šด ์ž๋ฐ” 9 ๋ชจ๋“ˆ ์‹œ์Šคํ…œ
  • 6๊ฐœ์›” ์ฃผ๊ธฐ์˜ ์ ์ง„์  ์ž๋ฐ” ๋ฆด๋ฆฌ์Šค ์ƒ๋ช…์ฃผ๊ธฐ
  • ์ฒซ ๋ฒˆ์งธ ์ ์ง„์  ๋ฆด๋ฆฌ์Šค ์ž๋ฐ” 10
  • ๋ฏธ๋ž˜ ์ž๋ฐ” ๋ฒ„์ „์— ์ถ”๊ฐ€๋˜๋ฆฌ๋ผ ๊ธฐ๋Œ€ํ•˜๋Š” ๊ธฐ๋Šฅ

21.1 ์ž๋ฐ” 8์˜ ๊ธฐ๋Šฅ ๋ฆฌ๋ทฐ

์ž๋ฐ” 8์—์„œ ํฐ ๋ณ€ํ™”๊ฐ€ ์ƒ๊ธด ์ด์œ 

  • ์ž๋ฐ” 8์— ์ถ”๊ฐ€๋œ ๋Œ€๋ถ€๋ถ„ ๊ธฐ๋Šฅ -> ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์‰ฝ๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์คŒ
  • ํฐ ๋ณ€ํ™”๊ฐ€ ์ƒ๊ธด ์ด์œ 
    • ๊ฐœ๋ณ„ CPU ์ฝ”์–ด ์†๋„๊ฐ€ ๋นจ๋ผ์ง€๋ฉฐ ๋ณ‘๋ ฌ ์‹คํ–‰์‹œ ์ฝ”๋“œ ์‹คํ–‰ ์†๋„ ํ–ฅ์ƒ ๊ฐ€๋Šฅ
    • ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋ฐ์ดํ„ฐ ์ปฌ๋ ‰์…˜์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•จ(๋ถˆ๋ณ€ ๊ฐ์ฒด, ๋ถˆ๋ณ€ ์ปฌ๋ ‰์…˜)

21.1.1 ๋™์ž‘ ํŒŒ๋ผ๋ฏธํ„ฐํ™”(๋žŒ๋‹ค์™€ ๋ฉ”์„œ๋“œ ์ฐธ์กฐ)

  • ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ์ง€์›ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋กœ ์ฝ”๋“œ ๋ธ”๋ก์„ ์ „๋‹ฌํ•˜๋Š” ๊ธฐ๋ฒ•
// Apple์— Predicate์˜ test์— ํ•ด๋‹นํ•˜๋Š” isGreenApple, isHeavyApple ๊ตฌํ˜„
public class Apple {
	public boolean isGreenApple() {
		return GREEN.equals(color);
	}
	public boolean isHeavyApple() {
		return weight > 150;
	}
}

// Predicate๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๋Š”๋‹ค
public List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> applePredicate) {
	List<Apple> result = new ArrayList<>();
	for(Apple apple : inventory) {
		if(applePredicate.test(apple)) {
			result.add(apple);
		}
	}

	return result;	
}

// stream์˜ filter๋ฅผ ์ด์šฉํ•˜๋ฉด ๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ‘œํ˜„ ๊ฐ€๋Šฅ
public List<Apple> filterApplesForStream(List<Apple> inventory, Predicate<Apple> applePredicate) {
	return inventory.stream().filter(applePredicate::test).collect(Collectors.toList());
}

// ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Œ
List<Apple> greenApples = filterApples(inventory, Apple::isGreenApple);
List<Apple> heavyApples = filterApples(inventory, Apple::isHeavyApple);

๋˜๋Š” ๋žŒ๋‹ค ํ‘œํ˜„์‹(lambda expression)์„ ์ด์šฉํ•˜์—ฌ ํ‘œํ˜„

List<Apple> redApples = filterApples(inventory, (Apple apple) -> RED.equals(apple.getColor()));
List<Apple> heavyApples2 = filterApples(inventory, (Apple apple) -> apple.getWeight() > 150);

21.1.2 ์ŠคํŠธ๋ฆผ

  • ์ŠคํŠธ๋ฆผ API๋Š” ํŒŒ์ดํ”„๋ผ์ธ์ด๋ผ๋Š” ๊ฒŒ์œผ๋ฅธ ํ˜•์‹์˜ ์—ฐ์‚ฐ์„ ์‚ฌ์šฉ
  • ํฐ ๋ฐ์ดํ„ฐ ์ง‘ํ•ฉ์ผ์ˆ˜๋ก ์ŠคํŠธ๋ฆผ์˜ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์ด ํšจ์œจ์ ์ด๋ฉฐ, ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ ๋“ฑ์˜ ๊ด€์ ์—์„œ๋„ ํƒ์ƒ‰ ํšŸ์ˆ˜๋ฅผ ์ตœ์†Œํ™” ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•จ
  • parallel ๋ฉ”์„œ๋“œ๋กœ ์ŠคํŠธ๋ฆผ์„ ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌ
/*
* 1. ํ†ตํ™”๋ณ„๋กœ ํŠธ๋žœ์žญ์…˜์„ ๊ทธ๋ฃนํ™”ํ•œ ๋‹ค์Œ์— ํ•ด๋‹น ํ†ตํ™”๋กœ ์ผ์–ด๋‚œ ๋ชจ๋“  ํŠธ๋žœ์žญ์…˜ ํ•ฉ๊ณ„๋ฅผ ๊ณ„์‚ฐํ•˜์‹œ์˜ค(Map<Currency, Integer>)
* 2. ํŠธ๋žœ์žญ์…˜์„ ๋น„์‹ผ ํŠธ๋žœ์žญ์…˜๊ณผ ์ €๋ ดํ•œ ํŠธ๋žœ์žญ์…˜ ๋‘ ๊ทธ๋ฃน์œผ๋กœ ๋ถ„๋ฅ˜ํ•˜์‹œ์˜ค(Map<Boolean, List<Transaction>>)
*/

// Collection ๋ฒ„์ „
Map<Currency, List<Transaction>> transactionsByCurrencies = new HashMap<>();
for (Transaction transaction : transactions) {
	Currency currency = transaction.getCurrency();
	List<Transaction> transactionsForCurrency = transactionsByCurrencies.get(currency);
	if (transactionsForCurrency == null) {
		transactionsForCurrency = new ArrayList<>();
		transactionsByCurrencies.put(currency, transactionsForCurrency);
	}
	transactionsForCurrency.add(transaction);
}

// Stream(ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ) ๋ฒ„์ „
Map<Currency, List<Transaction>> transactionsByCurrencies2 = transactions.stream().collect(groupingBy(Transaction::getCurrency));

21.1.3 CompletableFuture ํด๋ž˜์Šค

  • ์ž๋ฐ”5์˜ Future ์ธํ„ฐํŽ˜์ด์Šค : ์—ฌ๋Ÿฌ ์ž‘์—…์ด ๋™์‹œ์— ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋„๋ก ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋‚˜ ์ฝ”์–ด๋กœ ์ž‘์—…์„ ํ• ๋‹น ๊ฐ€๋Šฅ(๋ฉ€ํ‹ฐ์ฝ”์–ด ํ™œ์šฉ)
  • Future์™€ ๊ด€๋ จ๋œ ๊ณตํ†ต ๋””์ž์ธ ํŒจํ„ด์„ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์œผ๋กœ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก thenCompose, thenCombine, allOf ๋“ฑ์„ ์ œ๊ณต
    • ๋ช…๋ นํ˜•์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œ ๊ฐ์†Œํšจ๊ณผ

21.1.4 Optional ํด๋ž˜์Šค

  • T ํ˜•์‹์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜ Optional.empty(๊ฐ’์ด ์—†์Œ)๋ผ๋Š” ์ •์  ๋ฉ”์„œ๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” Optional<T> ํด๋ž˜์Šค
  • ๊ฐ’์ด ์—†์„ ๋•Œ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” null ๋Œ€์‹  ์ •ํ•ด์ง„ ๋ฐ์ดํ„ฐ ํ˜•์‹์„ ์ œ๊ณต
// BEFORE
String name = null;
if(insurance != null){
	name = insurance.getName();
}

// AFTER
Optional<Insurance> optInsurance = Optional.ofNullable(insurance);
Optional<String> name = optInsurance.map(Insurance::getName);

21.1.5 Flow API

  • ์ž๋ฐ”9์˜ ๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ, ๋ฆฌ์•กํ‹ฐ๋ธŒ ๋‹น๊น€ ๊ธฐ๋ฐ˜ ์—ญ์••๋ ฅ ํ”„๋กœํ† ํด ํ‘œ์ค€ํ™”
  • Flow API๋Š” ํ˜ธํ™˜์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋„๋ก ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ๋„ค ๊ฐœ์˜ ์ธํ„ฐํŽ˜์ด์Šค Publisher, Subscriber, Subscription, Processor ํฌํ•จ

21.1.6 ๋””ํดํŠธ ๋ฉ”์„œ๋“œ

  • ์ธํ„ฐํŽ˜์ด์Šค ์„ค๊ณ„์ž๊ฐ€ ๋ฉ”์„œ๋“œ์˜ ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ์ œ๊ณต ๊ฐ€๋Šฅ
  • ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„ ํด๋ž˜์Šค๋“ค์ด ์ƒˆ๋กœ ์ถ”๊ฐ€๋œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•„๋„ ๋จ
// ์ƒ์†๊ณผ ๊ด€๋ จ๋œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Œ..
public interface A {
      default void hello {
            print A
      }
}

public interface B extends A {
      default void hello {
            print B
      }
}

public class C implements B, A {
      public static void main(String... args) {
            new C().hello();	// print B
      }
}

21.2 ์ž๋ฐ” 9 ๋ชจ๋“ˆ ์‹œ์Šคํ…œ

  • ์ž๋ฐ” 9์—์„œ ์ถ”๊ฐ€๋œ ๋‚ด์šฉ
    • ์ŠคํŠธ๋ฆผ์˜ takeWhile, dropWhile ์ถ”๊ฐ€
    • CompletableFuture์˜ completeOnTimeout ์ถ”๊ฐ€
    • ๋ชจ๋“ˆ ์‹œ์Šคํ…œ - module-info.java ํŒŒ์ผ ์ถ”๊ฐ€
  • ๋‹ค๋ฅธ ๋ฆด๋ฆฌ์Šค์— ๋น„ํ•ด ๊ณผ๊ฑฐ ํ˜ธํ™˜์„ฑ์„ ํ•ด์ณค๋‹ค๋Š” ์˜๊ฒฌ
    • ๋ชจ๋“ˆํ™”๋ผ๋Š” ์žฅ์ ์„ ์–ป๊ธฐ ์œ„ํ•œ ๋ถˆ๊ฐ€ํ”ผํ•œ ํฌ์ƒ
  • ์ž๋ฐ” ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์ด ์ œ๊ณตํ•˜๋Š” ์žฅ์ 
    • ์•ˆ์ •์  ์„ค์ •
    • ๊ฐ•ํ•œ ์บก์Аํ™”
    • ๋ณด์•ˆ์„ฑ ๊ฐœ์„ 
    • ์„ฑ๋Šฅ ๊ฐœ์„ 
    • ํ™•์žฅ์„ฑ

21.3 ์ž๋ฐ” 10 ์ง€์—ญ ๋ณ€์ˆ˜ํ˜• ์ถ”๋ก 

  • ์ž๋ฐ”7 : ๋ณ€์ˆ˜๊ฐ€ ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•  ๋•Œ ์ปจํ…์ŠคํŠธ๋กœ ํ˜•์‹์„ ์œ ์ถ”ํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์—์„œ๋Š” ์ƒ๋žต ๊ฐ€๋Šฅ
Map<String, List<String>> myMap = new HashMap<String, List<String>>();
-> Map<String, List<String>> myMap = new HashMap<>();
  • ์ž๋ฐ”10 : ๋กœ์ปฌ๋ณ€์ˆ˜ ์„ ์–ธ์„ var๋ฅผ ์ด์šฉํ•˜์—ฌ ์ปดํŒŒ์ผ๋Ÿฌ์—๊ฒŒ ํƒ€์ž…์„ ์ถ”๋ก ํ•˜๊ฒŒํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•จ
var list = new ArrayList<String>(); // infers ArrayList<String> 
var stream = list.stream(); // infers Stream<String> 
var numbers = List.of(1, 2, 3, 4, 5); 
for (var number : numbers) { 
	System.out.println(number); 
} 
for (var i = 0; i < numbers.size(); i++) { 
	System.out.println(numbers.get(i)); 
}

์ž๋ฐ” 11์˜ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ

  • String ํด๋ž˜์Šค์˜ ์ƒˆ๋กœ์šด ๋ฉ”์„œ๋“œ
    • isBlank, lines, strip, stripLeading, stripTrailing, repeat
String multilineString = "Baeldung helps \n \n developers \n explore Java.";
List<String> lines = multilineString.lines()
                    .filter(line -> !line.isBlank())
                    .map(String::strip)
                    .collect(Collectors.toList());
assertThat(lines).containsExactly("Baeldung helps", "developers", "explore Java.");
  • Files ํด๋ž˜์Šค์— readString, writeString ์ถ”๊ฐ€
Path filePath = Files.writeString(Files.createTempFile(tempDir, "demo", ".txt"), "Sample text");
String fileContent = Files.readString(filePath);
assertThat(fileContent).isEqualTo("Sample text");
  • ์ปฌ๋ž™์…˜์˜ toArray() ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋กœ๋”ฉํ•˜๋Š” ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€ -> ์›ํ•˜๋Š” ํƒ€์ž…์˜ ๋ฐฐ์—ด ์„ ํƒ ๊ฐ€๋Šฅ
List<String> sampleList = Arrays.asList("Java", "Kotlin");
String[] sampleArray = sampleList.toArray(String[]::new);
  • Predicate ์ธํ„ฐํŽ˜์ด์Šค์— not ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€
  • ์ž๋ฐ” ์ปดํŒŒ์ผ์—†์ด ์‹คํ–‰ ๊ฐ€๋Šฅ
# before
$ javac HelloWorld.java
$ java HelloWorld 
Hello Java 8!

# after
$ java HelloWorld.java
Hello Java 11

๋งˆ๋ฌด๋ฆฌ

์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์›€์ด๋ผ๋Š” ์—ฌํ–‰์„ ์ฆ๊ฒผ๊ธธ ๋ฐ”๋ž€๋‹ค.
๊ทธ๋ฆฌ๊ณ  ์•ž์œผ๋กœ ์ผ์–ด๋‚  ์ž๋ฐ”์˜ ์ง„ํ™”๋ฅผ ์‚ดํŽด๋ณด๋Š” ๋ฐ ๋” ๋งŽ์€ ๊ด€์‹ฌ์ด ์ƒ๊ฒผ๊ธธ ํฌ๋งํ•œ๋‹ค

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