πΉ chap9. 리ν©ν°λ§, ν μ€ν , λλ²κΉ
9.1 κ°λ μ±κ³Ό μ μ°μ±μ κ°μ νλ 리ν©ν°λ§
9.1.1 μ½λ κ°λ μ± κ°μ
μ½λ κ°λ μ±μ΄ μ’λ€ β μ΄λ€ μ½λλ₯Ό λ€λ₯Έ μ¬λλ μ½κ² μ΄ν΄ν μ μλ€.
μ½λ κ°λ μ±μ κ°μ νλ€λ κ²μ μ°λ¦¬κ° ꡬνν μ½λλ₯Ό λ€λ₯Έ μ¬λμ΄ μ½κ² μ΄ν΄νκ³ μ μ§λ³΄μν μ μκ² λ§λλ κ²μ μλ―Ένλ€. μ½λ κ°λ μ±μ λμ΄λ €λ©΄ μ½λμ λ¬Έμνλ₯Ό μνκ³ , νμ€ μ½λ© κ·μΉμ μ€μνλ λ±μ λ Έλ ₯μ κΈ°μΈμ¬μΌ νλ€.
[ μ½λ κ°λ μ±μ κ°μ ν μ μλ μμ ]
- μ΅λͺ ν΄λμ€λ₯Ό λλ€ ννμμΌλ‘ 리ν©ν°λ§
- λλ€ ννμμ λ©μλ μ°Έμ‘°λ‘ λ¦¬ν©ν°λ§
- λͺ λ Ήν λ°μ΄ν° μ²λ¦¬λ₯Ό μ€νΈλ¦ΌμΌλ‘ 리ν©ν°λ§
9.1.2 μ΅λͺ ν΄λμ€λ₯Ό λλ€ ννμμΌλ‘ 리ν©ν°λ§νκΈ°
νλμ μΆμ λ©μλλ₯Ό ꡬννλ μ΅λͺ ν΄λμ€λ λλ€ ννμμΌλ‘ 리ν©ν°λ§ν μ μλ€.
- Runnable κ°μ²΄λ₯Ό λ§λλ μ΅λͺ ν΄λμ€μ μ΄μ λμνλ λλ€ ννμ
1
2
3
4
5
6
7
8
// μ΅λͺ
ν΄λμ€
Runnable r1 = new Runnable() {
public void run() {
System.out.println("Hello");
}
};
// λλ€ ννμ
Runnable r2 = () -> System.out.println("Hello");
νμ§λ§ λͺ¨λ μ΅λͺ ν΄λμ€λ₯Ό λλ€ ννμμΌλ‘ λ³νν μ μλ κ²μ μλλ€.
- μ΅λͺ
ν΄λμ€μμ μ¬μ©ν thisμ superλ λλ€ ννμμμ λ€λ₯Έ μλ―Έλ₯Ό κ°λλ€.
- μ΅λͺ ν΄λμ€ this : μ΅λͺ ν΄λμ€ μμ
- λλ€ this : λλ€λ₯Ό κ°μΈλ ν΄λμ€λ₯Ό κ°λ¦¬ν¨λ€
μ΅λͺ ν΄λμ€λ κ°μΈκ³ μλ ν΄λμ€μ λ³μλ₯Ό κ°λ¦΄ μ μλ€. (μλ λ³μ)
νμ§λ§ λλ€ ννμμΌλ‘λ λ³μλ₯Ό κ°λ¦΄ μ μλ€.
1 2 3 4 5 6 7 8 9 10 11 12
int a = 10; Runnable r1 = () -> { int a = 2; // μ»΄νμΌμλ¬ System.out.println(a); }; Runnable r2 = new Runnable() { public void run() { int a = 2; System.out.println(a); } };
μ΅λͺ ν΄λμ€λ λλ€ ννμμΌλ‘ λ°κΎΈλ©΄ μ½ν μ€νΈ μ€λ²λ‘λ©μ λ°λ₯Έ λͺ¨νΈν¨μ΄ μ΄λλ μ μλ€.
μ΅λͺ ν΄λμ€λ μΈμ€ν΄μ€νν λ λͺ μμ μΌλ‘ νμμ΄ μ ν΄μ§λ λ°λ©΄ λλ€μ νμμ μ½ν μ€νΈμ λ°λΌ λ¬λΌμ§κΈ° λλ¬Έμ΄λ€.
1 2 3 4 5
interface Task { public void execute(); } public static void doSomething(Runnable r){ r.run(); } public static void doSomething(Task a){ a.execute(); }
Taskλ₯Ό ꡬννλ μ΅λͺ ν΄λμ€λ₯Ό μ λ¬ν μ μλ€.
1 2 3 4 5 6
// Task μ§μ doSomething(new Task() { public void execute() { System.out.println("Danger danger!!"); } });
νμ§λ§ μ΅λͺ ν΄λμ€λ₯Ό λλ€ ννμμΌλ‘ λ°κΎΈλ©΄ λ©μλλ₯Ό νΈμΆν λ Runnableκ³Ό Task λͺ¨λ λμ νμμ΄ λ μ μμΌλ―λ‘ λ¬Έμ κ° μκΈ΄λ€.
1 2
// TaskμΈμ§ RunnableμΈμ§ λͺ νν μ μ μμ doSomething(() -> System.out.println("Danger danger!!");
μ¦, doSomething(Runnable)κ³Ό doSomething(Task) μ€ μ΄λ κ²μ κ°λ¦¬ν€λμ§ μ μ μλ λͺ¨νΈν¨μ΄ λ°μνλ€.
λͺ μμ νλ³ν (Task)λ₯Ό μ΄μ©ν΄ λͺ¨νΈν¨μ μ κ±°ν μ μλ€.
1 2
// λͺ μμ νλ³ν doSomething((Task)() -> System.out.println("Danger danger!!"));
νμ§λ§ λ·λΉμ¦μ IntelliJ λ±μ ν¬ν¨ν λλΆλΆμ ν΅ν© κ°λ° νκ²½(IDE)μμ μ 곡νλ 리ν©ν°λ§ κΈ°λ₯μ μ΄μ©νλ©΄ μ κ°μ λ¬Έμ κ° μλμΌλ‘ ν΄κ²°λλ€.
9.1.3 λλ€ ννμμ λ©μλ μ°Έμ‘°λ‘ λ¦¬ν©ν°λ§νκΈ°
λλ€ ννμ λμ λ©μλ μ°Έμ‘°λ₯Ό μ΄μ©νλ©΄ κ°λ μ±μ λμΌ μ μλ€.
λ©μλ μ°Έμ‘°μ λ©μλλͺ μΌλ‘ μ½λμ μλλ₯Ό λͺ ννκ² μ릴 μ μκΈ° λλ¬Έμ΄λ€.
1
2
3
4
5
6
7
8
9
// μΉΌλ‘리 μμ€μΌλ‘ μ리 κ·Έλ£Ήν
Map<CaloricLevel, List<Dish>> dishesByCaloricLevel =
menu.stream()
.collect(
groupingBy(dish -> {
if (dish.getCalories() <= 400) return CaloricLevel.DIET;
else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
else return CaloricLevel.FAT;
}));
λλ€ ννμμ λ³λμ λ©μλλ‘ μΆμΆν λ€μμ groupingByμ μΈμλ‘ μ λ¬ν μ μλ€. λ€μμ²λΌ μ½λκ° κ°κ²°νκ³ μλλ λͺ νν΄μ§λ€.
1
2
3
// λλ€ ννμμ λ©μλλ‘ μΆμΆ
Map<CaloricLevel, List<Dish>> dishesByCaloricLevel =
menu.stream().collect(groupingBy(Dish::getCaloricLevel));
μ΄μ Dish ν΄λμ€μ getCaloricLevel λ©μλλ₯Ό μΆκ°νλ€.
1
2
3
4
5
6
7
8
public class Dish {
...
public CaloricLevel getCaloricLevel() {
if (this.getCalories() <= 400) return CaloricLevel.DIET;
else if (this.getCalories() <= 700) return CaloricLevel.NORMAL;
else return CaloricLevel.FAT;
}
}
λν comparingκ³Ό maxBy κ°μ μ μ ν¬νΌ λ©μλλ₯Ό νμ©νλ κ²λ μ’λ€. μ΄λ€μ λ©μλ μ°Έμ‘°μ μ‘°νλ₯Ό μ΄λ£¨λλ‘ μ€κ³λμλ€.
1
2
3
4
5
// λΉκ΅ ꡬνμ μ κ²½ μ¨μΌ νλ€.
inventory.sort(
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
// μ½λκ° λ¬Έμ μ체λ₯Ό μ€λͺ
νλ€.
inventory.sort(comparing(Apple::getWeight));
sum, maximum λ± μμ£Ό μ¬μ©νλ 리λμ± μ°μ°μ λ©μλ μ°Έμ‘°μ ν¨κ» μ¬μ©ν μ μλ λ΄μ₯ ν¬νΌ λ©μλλ₯Ό μ 곡νλ€.
μ΅λκ°μ΄λ ν©κ³λ₯Ό κ³μ°ν λ λλ€ ννμκ³Ό μ μμ€ λ¦¬λμ± μ°μ°μ μ‘°ν©νλ κ²λ³΄λ€ Collectors APIλ₯Ό μ¬μ©νλ©΄ μ½λμ μλκ° λ λͺ νν΄μ§λ€.
1
2
3
4
// μ μμ€ λ¦¬λμ± μ°μ°μ μ‘°ν©ν μ½λ
int totalCalories =
menu.stream().map(Dish::getCalories)
.reduce(0, (c1, c2) -> c1 + c2);
λ΄μ₯ 컬λ ν°λ₯Ό μ΄μ©νλ©΄ μ½λ μμ²΄λ‘ λ¬Έμ λ₯Ό λ λͺ ννκ² μ€λͺ ν μ μλ€.
1
2
// 컬λ ν° summingIntλ₯Ό μ¬μ©(μμ μ΄ μ΄λ€ λμμ μννλμ§ λ©μλ μ΄λ¦μΌλ‘ μ€λͺ
)
int totalCalories = menu.stream().collect(summingInt(Dish::getCalories));
9.1.4 λͺ λ Ήν λ°μ΄ν° μ²λ¦¬λ₯Ό μ€νΈλ¦ΌμΌλ‘ 리ν©ν°λ§νκΈ°
μ€νΈλ¦Ό APIλ λ°μ΄ν° μ²λ¦¬ νμ΄νλΌμΈμ μλλ₯Ό λ λͺ νν 보μ¬μ£ΌκΈ° λλ¬Έμ λ°λ³΅μλ₯Ό μ΄μ©ν κΈ°μ‘΄μ λͺ¨λ 컬λ μ μ²λ¦¬ μ½λλ₯Ό μ€νΈλ¦Ό APIλ‘ λ°κΏμΌ νλ€.
μ€νΈλ¦Όμ μΌνΈμν·κ³Ό κ²μΌλ¦μ΄λΌλ κ°λ ₯ν μ΅μ νλΏ μλλΌ λ©ν°μ½μ΄ μν€ν μ²λ₯Ό νμ©ν μ μλ μ§λ¦κΈΈμ μ 곡νλ€.
λ€μ λͺ λ Ήν μ½λλ νν°λ§ + μΆμΆλ‘ μν¨ μ½λλ€.
ν΄λΉ μ½λλ μλλ₯Ό νμ νκΈ° μ΄λ ΅κ³ λ³λ ¬λ‘ μ€νμν€λ κ²μ΄ λ§€μ° μ΄λ ΅λ€.
1
2
3
4
5
6
List<String> dishNames = new ArrayList<>();
for(Dish dish: menu) {
if(dish.getCalories() > 300) {
dishNames.add(dish.getNames());
}
}
μ€νΈλ¦Ό APIλ₯Ό μ΄μ©νλ©΄ λ¬Έμ λ₯Ό λ μ§μ μ μΌλ‘ κΈ°μ ν μ μμ λΏ μλλΌ μ½κ² λ³λ ¬νν μ μλ€.
1
2
3
4
menu.parallelStream()
.filter(d -> d.getCalories() > 300)
.map(Dish::getName)
.collect(toList());
λͺ λ Ήν μ½λμ break, continue, return λ±μ μ μ΄ νλ¦λ¬Έμ λͺ¨λ λΆμν΄μ κ°μ κΈ°λ₯μ μννλ μ€νΈλ¦Ό μ°μ°μΌλ‘ μ μΆν΄μΌ νλ―λ‘ λͺ λ Ήν μ½λλ₯Ό μ€νΈλ¦Ό APIλ‘ λ°κΎΈλ κ²μ μ¬μ΄ μΌμ΄ μλλ€.
9.1.5 μ½λ μ μ°μ± κ°μ
λλ€ ννμμ μ΄μ©νλ©΄ λμ νλΌλ―Έν°νλ₯Ό μ½κ² ꡬνν μ μλ€. μ¦, λ€μν λλ€λ₯Ό μ λ¬ν΄μ λ€μν λμμ ννν μ μλ€. λ°λΌμ λ³ννλ μꡬμ¬νμ λμνλ μ½λλ₯Ό ꡬνν μ μλ€.
ex) νλ λμΌμ΄νΈλ‘ λ€μν νν°λ§ κΈ°λ₯ ꡬν, λΉκ΅μλ‘ λ€μν λΉκ΅ κΈ°λ₯ λ§λ€κΈ°
ν¨μν μΈν°νμ΄μ€ μ μ©
λλ€ ννμμ μ΄μ©νλ €λ©΄ ν¨μν μΈν°νμ΄μ€κ° νμνλ€. λ°λΌμ ν¨μν μΈν°νμ΄μ€λ₯Ό μ½λμ μΆκ°ν΄μΌ νλ€.
μ‘°κ±΄λΆ μ°κΈ° μ€ν(conditional deferred execution)κ³Ό μ€ν μ΄λΌμ΄λ(execute around) λ κ°μ§ μμ£Ό μ¬μ©νλ ν¨ν΄μΌλ‘ λλ€ ννμ 리ν©ν°λ§μ μ§ννλ€.
μ‘°κ±΄λΆ μ°κΈ° μ€ν
μ€μ μμ μ μ²λ¦¬νλ μ½λ λ΄λΆμ μ μ΄ νλ¦λ¬Έμ΄ 볡μ‘νκ² μ½ν μ½λλ₯Ό νν λ³Ό μ μλ€.
1
2
3
4
// λ΄μ₯ μλ° Logger ν΄λμ€λ₯Ό μ¬μ©νλ μμ
if (logger.isLoggable(Log.FINER)) {
logger.final("Problem: " + generateDiagnostic());
}
μ μ½λλ λ€μκ³Ό κ°μ λ¬Έμ κ° μλ€.
- loggerμ μνκ° isLoggableμ΄λΌλ λ©μλμ μν΄ ν΄λΌμ΄μΈνΈ μ½λλ‘ λ ΈμΆλλ€.
- λ©μμ§λ₯Ό λ‘κΉ ν λλ§λ€ logger κ°μ²΄μ μνλ₯Ό λ§€λ² νμΈνλ κ²μ μ½λλ₯Ό μ΄μ§λ½νλ κ² λΏμ΄λ€.
λ©μΈμ§λ₯Ό λ‘κΉ νκΈ° μ μ logger κ°μ²΄κ° μ μ ν μμ€μΌλ‘ μ€μ λμλμ§ λ΄λΆμ μΌλ‘ νμΈνλ log λ©μλλ₯Ό μ¬μ©νλ κ²μ΄ λ°λμ§νλ€.
1
logger.log(Level.FINER, "Problem: " + generateDiagnostic());
λλΆμ λΆνμν ifλ¬Έμ μ κ±°ν μ μμΌλ©° loggerμ μνλ₯Ό λ ΈμΆν νμκ° μλ€.
νμ§λ§ μΈμλ‘ μ λ¬λ λ©μΈμ§ μμ€μμ loggerκ° νμ±νλμ΄ μμ§ μλλΌλ νμ λ‘κΉ λ©μμ§λ₯Ό νκ°νκ² λλ€.
λλ€λ₯Ό μ΄μ©ν΄ ν΄λΉ λ¬Έμ λ₯Ό ν΄κ²°νλ€. νΉμ 쑰건(logger μμ€μ FINERλ‘ μ€μ )μμλ§ λ©μμ§κ° μμ±λ μ μλλ‘ λ©μμ§ μμ± κ³Όμ μ μ°κΈ°ν μ μμ΄μΌ νλ€.
μλ° 8 APIμμλ logger λ¬Έμ λ₯Ό ν΄κ²°ν μ μλλ‘ Supplierλ₯Ό μΈμλ‘ κ°λ μ€λ²λ‘λλ logλ©μλλ₯Ό μ 곡νλ€.
1
2
// μλ‘ μΆκ°λ log λ©μλμ μκ·Έλμ²
public void log(Level level, Supplier<String> msgSupplier)
λ€μμ²λΌ log λ©μλλ₯Ό νΈμΆν μ μλ€.
1
2
// λλ€ μ¬μ©
logger.log(Level.FINER, () -> "Problem: " + generateDiagnostic());
log λ©μλλ loggerμ μμ€μ΄ μ μ νκ² μ€μ λμ΄ μμ λλ§ μΈμλ‘ λκ²¨μ§ λλ€λ₯Ό λ΄λΆμ μΌλ‘ μ€ννλ€. λ€μμ log λ©μλμ λ΄λΆ ꡬν μ½λλ€.
1
2
3
4
5
public void log(Level level, Supplier<String> msgSupplier) {
if (logger.isLoggable(level)) {
log(level, msgSupplier.get()); // λλ€ μ€ν
}
}
λ§μ½ ν΄λΌμ΄μΈνΈ μ½λμμ κ°μ²΄ μνλ₯Ό μμ£Ό νμΈνκ±°λ(ex. loggerμ μν), κ°μ²΄μ μΌλΆ λ©μλλ₯Ό νΈμΆνλ μν©(ex. λ©μμ§ λ‘κΉ )μ΄λΌλ©΄ λ΄λΆμ μΌλ‘ κ°μ²΄μ μνλ₯Ό νμΈν λ€μμ λ©μλλ₯Ό νΈμΆ(λλ€λ λ©μλ μ°Έμ‘°λ₯Ό μΈμλ‘ μ¬μ©)νλλ‘ μλ‘μ΄ λ©μλλ₯Ό ꡬννλ κ²μ΄ μ’λ€. κ·Έλ¬λ©΄ μ½λ κ°λ μ±μ΄ μ’μμ§ λΏ μλλΌ μΊ‘μνλ κ°νλλ€(κ°μ²΄ μνκ° ν΄λΌμ΄μΈνΈ μ½λλ‘ λ ΈμΆλμ§ μλλ€)!
μ€ν μ΄λΌμ΄λ
λ§€λ² κ°μ μ€λΉ, μ’ λ£ κ³Όμ μ λ°λ³΅μ μΌλ‘ μννλ μ½λκ° μλ€λ©΄ μ΄λ₯Ό λλ€λ‘ λ³νν μ μλ€. μ€λΉ, μ’ λ£ κ³Όμ μ μ²λ¦¬νλ λ‘μ§μ μ¬μ¬μ©ν¨μΌλ‘μ¨ μ½λ μ€λ³΅μ μ€μΌ μ μλ€.
μλ μ½λλ νμΌμ μ΄κ³ λ«μ λ κ°μ λ‘μ§μ μ¬μ©νμ§λ§ λλ€λ₯Ό μ΄μ©ν΄ λ€μν λ°©μμΌλ‘ νμΌμ μ²λ¦¬ν μ μλλ‘ νλΌλ―Έν°νλμλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
String oneLine =
processFile((BufferedReader b) -> b.readLine()); // λλ€ μ λ¬
String twoLines =
processFile((BufferedReader b) -> b.readLine() + b.readLine()); // λ€λ₯Έ λλ€ μ λ¬
public static String processFile(BufferedReaderProcessor p) throws IOException {
try(BufferedReader br = new BufferedReader(new
FileReader("ModernJavaInAction/chap9/data.txt"))) {
return p.process(br); //μΈμλ‘ μ λ¬λ BufferedReaderProcessorλ₯Ό μ€ν
}
} // IOExceptionμ λμ§ μ μλ λλ€μ ν¨μν μΈν°νμ΄μ€
public interface BufferedReaderProcessor {
String process(BufferedReader b) throws IOException;
}
λλ€λ‘ BufferedReader κ°μ²΄μ λμμ κ²°μ ν μ μλ κ²μ ν¨μν μΈν°νμ΄μ€ BufferedReaderProcessor λλΆμ΄λ€.
9.2 λλ€λ‘ κ°μ²΄μ§ν₯ λμμΈ ν¨ν΄ 리ν©ν°λ§νκΈ°
μΈμ΄μ μλ‘μ΄ κΈ°λ₯μ΄ μΆκ°λλ©΄μ κΈ°μ‘΄ μ½λ ν¨ν΄μ΄λ κ΄μ©μ½λμ μΈκΈ°κ° μκΈ°λ νλ€.
μλ° 5: for-each 루νλ μλ¬ λ°μλ₯ μ΄ μ μΌλ©° κ°κ²°νλ―λ‘ κΈ°μ‘΄μ λ°λ³΅μ μ½λλ₯Ό λ체νλ€.
μλ° 7: λ€μ΄μλͺ¬λ μ°μ°μ <> λλ¬Έμ κΈ°μ‘΄μ μ λ€λ¦ μΈμ€ν΄μ€λ₯Ό λͺ μμ μΌλ‘ μμ±νλ λΉλκ° μ€μλ€.
λ€μν ν¨ν΄μ μ νλ³λ‘ μ 리ν κ²μ΄ λμμΈ ν¨ν΄(design pattern)μ΄λ€.
λμμΈ ν¨ν΄μ 곡ν΅μ μΈ μννΈμ¨μ΄ λ¬Έμ λ₯Ό μ€κ³ν λ μ¬μ¬μ©ν μ μλ κ²μ¦λ μ²μ¬μ§μ μ 곡νλ€. λͺ κ°μ§ μμλ λ€μκ³Ό κ°λ€.
- ꡬ쑰체μ λμνλ μκ³ λ¦¬μ¦μ μλ‘ λΆλ¦¬νκ³ μΆμ λ λ°©λ¬Έμ λμμΈ ν¨ν΄μ μ¬μ©ν μ μλ€.
- μ±κΈν΄ ν¨ν΄μ μ΄μ©ν΄μ ν΄λμ€ μΈμ€ν΄μ€νλ₯Ό νλμ κ°μ²΄λ‘ μ νν μ μλ€.
λλ€λ₯Ό μ΄μ©νλ©΄ λμμΈ ν¨ν΄μΌλ‘ ν΄κ²°νλ λ¬Έμ λ₯Ό λ κ°λ¨νκ² ν΄κ²°νκ³ , κΈ°μ‘΄μ λ§μ κ°μ²΄μ§ν₯ λμμΈ ν¨ν΄μ μ κ±°νκ±°λ κ°κ²°νκ² μ¬κ΅¬νν μ μλ€.
λ€μ λ€μ― κ°μ§ ν¨ν΄μ μ΄ν΄λ³Έλ€.
- μ λ΅(strategy)
- ν νλ¦Ώ λ©μλ(template method)
- μ΅μ λ²(observer)
- μ무 체μΈ(chain of responsibility)
- ν©ν 리(factory)
9.2.1 μ λ΅
- μ λ΅ ν¨ν΄
ν μ νμ μκ³ λ¦¬μ¦μ 보μ ν μνμμ λ°νμμ μ μ ν μκ³ λ¦¬μ¦μ μ ννλ κΈ°λ²
κ·Έλ¦Όκ³Ό κ°μ΄ μ λ΅ ν¨ν΄μ μΈ λΆλΆμΌλ‘ ꡬμ±λλ€.
- μκ³ λ¦¬μ¦μ λνλ΄λ μΈν°νμ΄μ€(Strategy μΈν°νμ΄μ€)
- λ€μν μκ³ λ¦¬μ¦μ λνλ΄λ ν κ° μ΄μμ μΈν°νμ΄μ€ ꡬν(ConcreteStrategyA, ConcreteStrategyB κ°μ ꡬ체μ μΈ κ΅¬ν ν΄λμ€)
- μ λ΅ κ°μ²΄λ₯Ό μ¬μ©νλ ν κ° μ΄μμ ν΄λΌμ΄μΈνΈ
μλ₯Ό λ€μ΄ μ€μ§ μλ¬Έμ λλ μ«μλ‘ μ΄λ£¨μ΄μ ΈμΌ νλ λ± ν μ€νΈ μ λ ₯μ΄ λ€μν 쑰건μ λ§κ² ν¬λ§· λμ΄ μλμ§ κ²μ¦νλ€κ³ κ°μ νμ. λ¨Όμ String λ¬Έμμ΄μ κ²μ¦νλ μΈν°νμ΄μ€λΆν° ꡬννλ€.
1
2
3
public interface ValidationStrategy {
boolean execute(String s);
}
μ΄λ²μλ μμμ μ μν μΈν°νμ΄μ€λ₯Ό ꡬννλ ν΄λμ€λ₯Ό νλ μ΄μ μ μνλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
// μ€μ§ μλ¬Έμλ‘ μ΄λ£¨μ΄μ‘λμ§ κ²μ¦
public class IsAllLowerCase implements ValidationStrategy {
public boolean execute(String s) {
return s.matches("[a-z]+");
}
}
// μ€μ§ μ«μλ‘ μ΄λ£¨μ΄μ‘λμ§ κ²μ¦
public class IsNumeric implements ValidationStrategy {
public boolean execute(String s) {
return s.matches("\\d+");
}
}
μ§κΈκΉμ§ ꡬνν ν΄λμ€λ₯Ό λ€μν κ²μ¦ μ λ΅μΌλ‘ νμ©ν μ μλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Validator {
private final ValidationStrategy strategy;
public Validator(ValidationStrategy v) {
this.strategy = v;
}
public boolean validate(String s) {
return strategy.execute(s);
}
}
Validator numericValidator = new Validator(new IsNumeric());
boolean b1 = numericValidator.validate("aaaa"); // false λ°ν
Validator lowerCaseValidator = new Validator(new IsAllLovwerCase());
boolean b2 = lowerCaseValidator.validate("bbbb"); // true λ°ν
λλ€ ννμ μ¬μ©
ValidationStrategyλ ν¨μν μΈν°νμ΄μ€λ©° Predicate
1
2
3
4
5
6
7
Validator numericValidator =
new Validator((String s) -> s.matches("[a-z]+")); // λλ€λ₯Ό μ§μ μ λ¬
boolean b1 = numericValidator.validate("aaaa");
Validator lowerCaseValidator =
new Validator((String s) -> s.matches("\\d+")); // λλ€λ₯Ό μ§μ μ λ¬
boolean b2 = lowerCaseValidator.validate("bbbb");
μ μ½λμμ νμΈν μ μλ―μ΄ λλ€ ννμμ μ΄μ©νλ©΄ μ λ΅ λμμΈ ν¨ν΄μμ λ°μνλ μμν μ½λλ₯Ό μ κ±°ν μ μλ€. λλ€ ννμμ μ½λ μ‘°κ°(λλ μ λ΅)μ μΊ‘μννλ€. μ¦, λλ€ ννμμΌλ‘ μ λ΅ λμμΈ ν¨ν΄μ λμ ν μ μλ€.
9.2.2 ν νλ¦Ώ λ©μλ
- ν νλ¦Ώ λ©μλ
βμ΄ μκ³ λ¦¬μ¦μ μ¬μ©νκ³ μΆμλ° κ·Έλλ‘λ μ λκ³ μ‘°κΈ κ³ μ³μΌ νλβ μν©μ μ ν©νλ€.
κ°λ¨ν μ¨λΌμΈ λ± νΉ μ ν리μΌμ΄μ μ ꡬννλ€κ³ κ°μ νμ. μ¬μ©μκ° κ³ κ° IDλ₯Ό μ ν리μΌμ΄μ μ μ λ ₯νλ©΄ μν λ°μ΄ν°λ² μ΄μ€μμ κ³ κ° μ 보λ₯Ό κ°μ Έμ€κ³ κ³ κ°μ΄ μνλ μλΉμ€λ₯Ό μ 곡ν μ μλ€.
μλ₯Ό λ€μ΄ κ³ κ° κ³μ’μ 보λμ€λ₯Ό μ κΈνλ€κ³ κ°μ νμ. μνλ§λ€ λ€μν μ¨λΌμΈ λ± νΉ μ ν리μΌμ΄μ μ μ¬μ©νλ©° λμ λ°©λ²λ λ€λ₯΄λ€. λ€μμ μ¨λΌμΈ λ± νΉ μ ν리μΌμ΄μ μ λμμ μ μνλ μΆμ ν΄λμ€λ€.
1
2
3
4
5
6
7
abstract class OnlineBanking {
public void processCustomer(int id) {
Customer c = Database.getCustomerWithId(id);
makeCustomerHappy(c);
}
abstract void makeCustomerHappy(Customer c);
}
processCustomer λ©μλλ μ¨λΌμΈ λ± νΉ μκ³ λ¦¬μ¦μ΄ ν΄μΌ ν μΌμ 보μ¬μ€λ€. μ°μ μ£Όμ΄μ§ κ³ κ° IDλ₯Ό μ΄μ©ν΄μ κ³ κ°μ λ§μ‘±μμΌμΌ νλ€. κ°κ°μ μ§μ μ OnlineBanking ν΄λμ€λ₯Ό μμλ°μ makeCustomerHappy λ©μλκ° μνλ λμμ μννλλ‘ κ΅¬νν μ μλ€.
λλ€ ννμ μ¬μ©
λλ€λ λ©μλ μ°Έμ‘°λ‘ μκ³ λ¦¬μ¦μ μΆκ°ν λ€μν μ»΄ν¬λνΈλ₯Ό ꡬνν μ μλ€.
μ΄μ μ μ μν makeCustomerHappyμ λ©μλ μκ·Έλμ²μ μΌμΉνλλ‘ Consumer
1
2
3
4
public void processCustomer(int id, Consumer<Customer> makeCustomerHappy) {
Customer c = Database.getCustomerWithId(id);
makeCustomerHappy.accept(c);
}
μ΄μ onlineBanking ν΄λμ€λ₯Ό μμλ°μ§ μκ³ μ§μ λλ€ ννμμ μ λ¬ν΄μ λ€μν λμμ μΆκ°ν μ μλ€.
1
2
new OnlineBankingLambda().processCustomer(1337, (Customer c) ->
System.out.println("Hello " + c.getName());
λλ€ ννμμ μ΄μ©νλ©΄ ν νλ¦Ώ λ©μλ λμμΈ ν¨ν΄μμ λ°μνλ μμν μ½λλ μ κ±°ν μ μλ€.
9.2.3 μ΅μ λ²
- μ΅μ λ² λμμΈ ν¨ν΄
μ΄λ€ μ΄λ²€νΈκ° λ°μνμ λ ν κ°μ²΄(μ£Όμ )κ° λ€λ₯Έ κ°μ²΄ 리μ€νΈ(μ΅μ λ²)μκ² μλμΌλ‘ μλ¦Όμ 보λ΄μΌ νλ μν©μμ μ¬μ©
- GUI μ ν리μΌμ΄μ μμ μ΅μ λ² ν¨ν΄μ΄ μμ£Ό λ±μ₯νλ€. λ²νΌ κ°μ GUI μ»΄ν¬λνΈμ μ΅μ λ²λ₯Ό μ€μ ν μ μλ€. κ·Έλ¦¬κ³ μ¬μ©μκ° λ²νΌμ ν΄λ¦νλ©΄ μ΅μ λ²μ μλ¦Όμ΄ μ λ¬λκ³ μ ν΄μ§ λμμ΄ μνλλ€.
- μ£Όμμ κ°κ²©(μ£Όμ ) λ³λμ λ°μνλ λ€μμ κ±°λμ(μ΅μ λ²) μμ μμλ μ΅μ λ² ν¨ν΄μ μ¬μ©ν μ μλ€.
μ΅μ λ² ν¨ν΄μΌλ‘ νΈμν° κ°μ 컀μ€ν°λ§μ΄μ¦λ μλ¦Ό μμ€ν μ μ€κ³νκ³ κ΅¬νν μ μλ€. λ€μν μ λ¬Έ 맀체(λ΄μνμμ€, κ°λμΈ, λ₯΄λͺ½λ)κ° λ΄μ€ νΈμμ ꡬλ νκ³ μμΌλ©° νΉμ ν€μλλ₯Ό ν¬ν¨νλ νΈμμ΄ λ±λ‘λλ©΄ μλ¦Όμ λ°κ³ μΆμ΄νλ€.
μ°μ λ€μν μ΅μ λ²λ₯Ό κ·Έλ£Ήνν Observer μΈν°νμ΄μ€κ° νμνλ€.
Observer μΈν°νμ΄μ€λ μλ‘μ΄ νΈμμ΄ μμ λ μ£Όμ (Feed)κ° νΈμΆν μ μλλ‘ notifyλΌκ³ νλ νλμ λ©μλλ₯Ό μ 곡νλ€.
1
2
3
interface Observer {
void notify(String tweet);
}
μ΄μ νΈμμ ν¬ν¨ν λ€μν ν€μλμ λν λμμ μνν μ μλ μ¬λ¬ μ΅μ λ²λ₯Ό μ μν μ μλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class NYTimes implements Observer {
public void notify(String tweet) {
if(tweet != null && tweet.contains("money")) {
System.out.println("Breaking news in NY! " + tweet);
}
}
}
class Guardian implements Observer {
public void notify(String tweet) {
if(tweet != null && tweet.contains("queen")) {
System.out.println("Yet more news from London..." + tweet);
}
}
}
class LeMonde implements Observer {
public void notify(String tweet) {
if(tweet != null && tweet.contains("wine")) {
System.out.println("Today cheese, wine and news! " + tweet);
}
}
}
κ·Έλ¦¬κ³ μ£Όμ λ ꡬνν΄μΌ νλ€. λ€μμ Subject μΈν°νμ΄μ€μ μ μλ€.
1
2
3
4
interface Subject {
void registerObserver(Observer o);
void notifyObservers(String tweet);
}
μ£Όμ λ registerObsesrver λ©μλλ‘ μλ‘μ΄ μ΅μ λ²λ₯Ό λ±λ‘ν λ€μμ notifyObservers λ©μλλ‘ νΈμμ μ΅μ λ²μ μ΄λ₯Ό μλ¦°λ€.
1
2
3
4
5
6
7
8
9
class Feed implements Subject {
private final List<Observer> observers = new ArrayList<>();
public void registerObserver(Observer o) {
this.observers.add(o);
}
public void notifyObservers(String tweet) {
observers.forEach(o -> o.notify(tweet));
}
}
Feedλ νΈμμ λ°μμ λ μλ¦Όμ λ³΄λΌ μ΅μ λ² λ¦¬μ€νΈλ₯Ό μ μ§νλ€. μ΄μ μ£Όμ μ μ΅μ λ²λ₯Ό μ°κ²°νλ λ°λͺ¨ μ ν리μΌμ΄μ μ λ§λ€ μ μλ€.
1
2
3
4
5
Feed f = new Feed();
f.registerObserver(new NYTimes());
f.registerObserver(new Guardian());
f.registerObserver(new LeMonde());
f.notifyObservers("The queen said her favorite book is Modern Java in Action!");
κ°λμΈλ μ°λ¦¬μ νΈμμ λ°μλ³Ό μ μκ² λμλ€.
λλ€ ννμ μ¬μ©νκΈ°
μΈ κ°μ μ΅μ λ²λ₯Ό λͺ μμ μΌλ‘ μΈμ€ν΄μ€ννμ§ μκ³ λλ€ ννμμ μ§μ μ λ¬ν΄μ μ€νν λμμ μ§μ ν μ μλ€.
1
2
3
4
5
6
7
8
9
10
f.registerObserver((String tweet) -> {
if(tweet != null && tweet.contains(" money ")) {
System.out.println("Breaking news in NY! " + tweet);
}
});
f.registerObserver((String tweet) -> {
if(tweet != null && tweet.contains(" queen ")) {
System.out.println("Yet more news from London... " + tweet);
}
});
9.2.4 μ무 체μΈ
- μ무 μ²΄μΈ ν¨ν΄
μμ μ²λ¦¬ κ°μ²΄μ 체μΈ(λμ μ²΄μΈ λ±)μ λ§λ€ λ μ¬μ©
ν κ°μ²΄κ° μ΄λ€ μμ μ μ²λ¦¬ν λ€μμ λ€λ₯Έ κ°μ²΄λ‘ κ²°κ³Όλ₯Ό μ λ¬νκ³ , λ€λ₯Έ κ°μ²΄λ ν΄μΌ ν μμ μ μ²λ¦¬ν λ€μμ λ λ€λ₯Έ κ°μ²΄λ‘ μ λ¬νλ μμ΄λ€.
μΌλ°μ μΌλ‘ λ€μμΌλ‘ μ²λ¦¬ν κ°μ²΄ μ 보λ₯Ό μ μ§νλ νλλ₯Ό ν¬ν¨νλ μμ μ²λ¦¬ μΆμ ν΄λμ€λ‘ μ무 μ²΄μΈ ν¨ν΄μ ꡬμ±νλ€. μμ μ²λ¦¬ κ°μ²΄κ° μμ μ μμ μ λλμΌλ©΄ λ€μ μμ μ²λ¦¬ κ°μ²΄λ‘ κ²°κ³Όλ₯Ό μ λ¬νλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// μμ
μ²λ¦¬ κ°μ²΄ μμ μ½λ
public abstract class ProcessingObject<T> {
protected ProcessingObject<T> successor;
public void setSuccessor(ProcessingObject<T> succesor) {
this.successor = successor;
}
public T handle(T input) {
T r = handleWork(input);
if(successor != null) {
return successor.handle(r);
}
return r;
}
abstract protected T handleWork(T input);
}
handle λ©μλλ μΌλΆ μμ μ μ΄λ»κ² μ²λ¦¬ν΄μΌ ν μ§ μ 체μ μΌλ‘ κΈ°μ νλ€. ProcessingObject ν΄λμ€λ₯Ό μμλ°μ handleWork λ©μλλ₯Ό ꡬννμ¬ λ€μν μ’ λ₯μ μμ μ²λ¦¬ κ°μ²΄λ₯Ό λ§λ€ μ μλ€.
λ€μμ λ μμ μ²λ¦¬ κ°μ²΄λ ν μ€νΈλ₯Ό μ²λ¦¬νλ μμ λ€(μ ν¨ν΄ νμ© μμ )
1
2
3
4
5
6
7
8
9
10
11
public class HeaderTextProcessing extends ProcessingObject<String> {
public String handleWork(String text) {
return "From Raoul, Mario and Alan: " + text;
}
}
public class SpellCheckerProcessing extends ProcessingObject<String> {
public String handleWork(String text) {
return text.replaceAll("labda", "lambda");
}
}
λ μμ μ²λ¦¬ κ°μ²΄λ₯Ό μ°κ²°ν΄μ μμ 체μΈμ λ§λ€ μ μλ€.
1
2
3
4
5
6
ProcessingObject<String> p1 = new HeaderTextProcessing();
ProcessingObject<String> p2 = new SpellCheckerProcessing();
p1.setSuccessor(p2); // λ μμ
μ²λ¦¬ κ°μ²΄λ₯Ό μ°κ²°νλ€.
String result = p1.handle("Aren't labdas really sexy?!!");
System.out.println(result);
// 'From Raoul, Mario and Alan: Aren't lambdas really sexy?!!' μΆλ ₯
λλ€ ννμ μ¬μ©
μ ν¨ν΄μ ν¨μ 체μΈ(ν¨μ μ‘°ν©)κ³Ό λΉμ·νλ€.
μμ
μ²λ¦¬ κ°μ²΄λ₯Ό Function<String, String>, λ μ νν νννμλ©΄ UnaryOperator
1
2
3
4
5
6
7
UnaryOperator<String> headerProcessing =
(String text) -> "From Raoul, Mario and Alan: " + text; // 첫 λ²μ§Έ μμ
μ²λ¦¬ κ°μ²΄
UnaryOperator<String> spellCheckerProcessing =
(String text) -> text.replaceAll("labda", "lambda"); // λ λ²μ§Έ μμ
μ²λ¦¬ κ°μ²΄
Function<String, String> pipeline =
headerProcessing.andThen(spellCheckerProcessing); // λμ 체μΈμΌλ‘ λ ν¨μλ₯Ό μ‘°ν©νλ€.
String result = pipeline.apply("Aren't labdas really sexy?!!");
9.2.5 ν©ν 리
- ν©ν 리 λμμΈ ν¨ν΄
μΈμ€ν΄μ€ν λ‘μ§μ ν΄λΌμ΄μΈνΈμ λ ΈμΆνμ§ μκ³ κ°μ²΄λ₯Ό λ§λ€ λ μ¬μ©
μλ₯Ό λ€μ΄ μνμμ μ·¨κΈνλ λμΆ, μ±κΆ, μ£Όμ λ± λ€μν μνμ λ§λ€μ΄μΌ νλ€κ³ κ°μ νμ. λ€μ μ½λμμ 보μ¬μ£Όλ κ²μ²λΌ λ€μν μνμ λ§λλ Factory ν΄λμ€κ° νμνλ€.
1
2
3
4
5
6
7
8
9
10
public class ProductFactory {
public static Product createProduct(String name) {
switch(name){
case " loan " : return new Loan();
case " stock " : return new Stock();
case " bond " : return new Bond();
default: throw new RuntimeException("No such product " + name);
}
}
}
μ¬κΈ°μ Loan, Stock, Bond λͺ¨λ Productμ μλΈνμμ΄λ€. createProduct λ©μλλ μμ°λ μνμ μ€μ νλ λ‘μ§μ ν¬ν¨ν μ μλ€.
μ΄λ λΆκ°μ μΈ κΈ°λ₯μΌ λΏ μ μ½λμ μ§μ§ μ₯μ μ μμ±μμ μ€μ μ μΈλΆλ‘ λ ΈμΆνμ§ μμμΌλ‘μ¨ ν΄λΌμ΄μΈνΈκ° λ¨μνκ² μνμ μμ°ν μ μλ€λ κ²μ΄λ€.
1
Product p = ProductFactory.createProduct("loan");
λλ€ ννμ μ¬μ©
μμ±μλ λ©μλ μ°Έμ‘°μ²λΌ μ¬μ©ν μ μλ€.
λ€μμ Loan μμ±μλ₯Ό μ¬μ©νλ μ½λλ€.
1
2
Supplier<Product> loanSupplier = Loan::new;
Loan loan = loanSupplier.get();
μ΄μ λ€μ μ½λμ²λΌ μνλͺ μ μμ±μλ‘ μ°κ²°νλ Mapμ λ§λ€μ΄μ μ½λλ₯Ό μ¬κ΅¬νν μ μλ€.
1
2
3
4
5
6
final static Map<String, Supplier<Product>> map = new HashMap<>();
static {
map.put("loan", Loan::new);
map.put("stock", Stock::new);
map.put("bond", Bond::new);
}
μ΄μ Mapμ μ΄μ©ν΄μ ν©ν 리 λμμΈ ν¨ν΄μμ νλ κ²μ²λΌ λ€μν μνμ μΈμ€ν΄μ€νν μ μλ€.
1
2
3
4
5
public static Product createProduct(String name) {
Supplier<Product> p = map.get(name);
if(p != null) return p.get();
throw new IllegalArgumentException("No such product " + name);
}
ν©ν 리 ν¨ν΄μ΄ μννλ μμ μ μλ° 8μ μλ‘μ΄ κΈ°λ₯μΌλ‘ κΉλνκ² μ 리νλ€.
νμ§λ§ ν©ν 리 λ©μλ createProductκ° μν μμ±μλ‘ μ¬λ¬ μΈμλ₯Ό μ λ¬νλ μν©μμλ μ΄ κΈ°λ²μ μ μ©νκΈ° μ΄λ ΅λ€. λ¨μν Supplier ν¨μν μΈν°νμ΄μ€λ‘λ μ΄ λ¬Έμ λ₯Ό ν΄κ²°ν μ μλ€.
μλ₯Ό λ€μ΄ μΈ μΈμ(Integer λκ°, λ¬Έμμ΄ νλ)λ₯Ό λ°λ μνμ μμ±μκ° μλ€κ³ κ°μ νμ. μΈ μΈμλ₯Ό μ§μνλ €λ©΄ TriFunctionμ΄λΌλ νΉλ³ν ν¨μν μΈν°νμ΄μ€λ₯Ό λ§λ€μ΄μΌ νλ€. κ²°κ΅ λ€μμ½λμ²λΌ Mapμ μκ·Έλμ²κ° 볡μ‘ν΄μ§λ€.
1
2
3
4
5
public interface TriFunction<T, U, V, R> {
R apply(T t, U u, V v);
}
Map<String, TriFunction<Integer, Integer, String, Product>> map
= new HashMap<>();
9.3 λλ€ ν μ€ν
νλ‘κ·Έλ¨μ΄ μλλλ‘ λμνλμ§ νμΈν μ μλ λ¨μ ν μ€ν μ μ§νν΄μΌ νλ€. μμ€ μ½λμ μΌλΆκ° μμλ κ²°κ³Όλ₯Ό λμΆν κ²μ΄λΌ λ¨μΈνλ ν μ€νΈ μΌμ΄μ€λ₯Ό ꡬννλ€.
μλ₯Ό λ€μ΄ λ€μμ²λΌ κ·Έλν½ μ ν리μΌμ΄μ μ μΌλΆμΈ Point ν΄λμ€κ° μλ€κ³ κ°μ νμ.
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Point {
private final int x;
private final int y;
private Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() { return x; }
public int getY() { return y; }
public Point moveRightBy(int x) {
return new Point(this.x + x, this.y);
}
}
λ€μμ moveRightBy λ©μλκ° μλν λλ‘ λμνλμ§ νμΈνλ λ¨μ ν μ€νΈλ€.
1
2
3
4
5
6
7
@Test
public void testMoveRightBy() throws Exception {
Point p1 = new Point(5, 5);
Point p2 = p1.moveRightBy(10);
assertEquals(15, p2.getX());
assertEquals(5, p2.getY());
}
9.3.1 보μ΄λ λλ€ ννμμ λμ ν μ€ν
moveRightByλ public μ΄λ―λ‘ μ μ½λλ λ¬Έμ μμ΄ μλνλ€. λ°λΌμ ν μ€νΈ μΌμ΄μ€ λ΄λΆμμ Point ν΄λμ€ μ½λλ₯Ό ν μ€νΈν μ μλ€. νμ§λ§ λλ€λ μ΅λͺ (κ²°κ΅ μ΅λͺ ν¨μ)μ΄λ―λ‘ ν μ€νΈ μ½λ μ΄λ¦μ νΈμΆν μ μλ€.
λ°λΌμ νμνλ€λ©΄ λλ€λ₯Ό νλμ μ μ₯ν΄μ μ¬μ¬μ©ν μ μμΌλ©° λλ€μ λ‘μ§μ ν μ€νΈν μ μλ€. λ©μλλ₯Ό νΈμΆνλ κ²μ²λΌ λλ€λ₯Ό μ¬μ©νλ€.
μλ₯Ό λ€μ΄ Point ν΄λμ€μ compareByXAndThenYλΌλ μ μ νλλ₯Ό μΆκ°νλ€κ³ κ°μ νμ(compareByXAndThenYλ₯Ό μ΄μ©νλ©΄ λ©μλ μ°Έμ‘°λ‘ μμ±ν Comparator κ°μ²΄μ μ κ·Όν μ μλ€).
1
2
3
4
5
public class Point {
public final static Comparator<Point> compareByXAndThenY =
comparing(Point::getX).thenComparing(Point::getY);
...
}
λλ€ ννμμ ν¨μν μΈν°νμ΄μ€μ μΈμ€ν΄μ€λ₯Ό μμ±νλ€λ μ¬μ€μ κΈ°μ΅νμ. λ°λΌμ μμ±λ μΈμ€ν΄μ€μ λμμΌλ‘ λλ€ ννμμ ν μ€νΈν μ μλ€.
1
2
3
4
5
6
7
@Test
public void testCompaingTwoPoints() throws Exception {
Point p1 = new Point(10, 15);
Point p2 = new Point(10, 20);
int result = Point.compareByXAndThenY.compare(p1, p2);
assertTrue(result < 0);
}
9.3.2 λλ€λ₯Ό μ¬μ©νλ λ©μλμ λμμ μ§μ€νλΌ
λλ€μ λͺ©νλ μ ν΄μ§ λμμ λ€λ₯Έ λ©μλμμ μ¬μ©ν μ μλλ‘ νλμ μ‘°κ°μΌλ‘ μΊ‘μννλ κ²μ΄λ€. κ·Έλ¬λ €λ©΄ μΈλΆ ꡬνμ ν¬ν¨νλ λλ€ ννμμ 곡κ°νμ§ λ§μμΌ νλ€.
λλ€ ννμμ μ¬μ©νλ λ©μλμ λμμ ν μ€νΈν¨μΌλ‘μ¨ λλ€λ₯Ό 곡κ°νμ§ μμΌλ©΄μλ λλ€ ννμμ κ²μ¦ν μ μλ€.
1
2
3
4
5
public static List<Point> moveAllPointsRightBy(List<Point> points, int x) {
return points.stream()
.map(p -> new Point(p.getX() + x, p.getY()))
.collect(toList());
}
μ μ½λμ λλ€ ννμ p β new Point(p.getX() + p.getY());λ₯Ό ν μ€νΈνλ λΆλΆμ μλ€. κ·Έλ₯ moveAllPointsRightBy λ©μλλ₯Ό ꡬνν μ½λμΌ λΏμ΄λ€. μ΄μ moveAllPointsRightBy λ©μλμ λμμ νμΈν μ μλ€.
1
2
3
4
5
6
7
8
9
@Test
public void testMoveAllPointsRightBy() throws Exception {
List<Point> points =
Arrays.asList(new Point(5, 5), new Point(10, 5));
List<Point> expectedPoints =
Arrays.asList(new Point(15, 5), new Point(20, 5));
List<Point> newPoints = Point.moveAllPointsRightBy(points, 10);
assertEquals(expectedPoints, newPoints);
}
9.3.3 볡μ‘ν λλ€λ₯Ό κ°λ³ λ©μλλ‘ λΆν νκΈ°
ν μ€νΈ μ½λμμ λλ€ ννμμ μ°Έμ‘°ν μ μλλ°, ν κ°μ§ ν΄κ²°μ± μ 9.1.3μ μμ μ€λͺ ν κ² μ²λΌ λλ€ ννμμ λ©μλ μ°Έμ‘°λ‘ λ°κΎΈλ κ²μ΄λ€(μλ‘μ΄ μΌλ° λ©μλ μ μΈ). κ·Έλ¬λ©΄ μΌλ° λ©μλλ₯Ό ν μ€νΈνλ―μ΄ λλ€ ννμμ ν μ€νΈν μ μλ€.
9.3.4 κ³ μ°¨μ ν¨μ ν μ€ν
- κ³ μ°¨μ ν¨μ
ν¨μλ₯Ό μΈμλ‘ λ°κ±°λ λ€λ₯Έ ν¨μλ₯Ό λ°ννλ λ©μλ
κ³ μ°¨μ ν¨μλ₯Ό ν μ€ν νλ κ²μ μ΄λ ΅λ€. λ©μλκ° λλ€λ₯Ό μΈμλ‘ λ°λλ€λ©΄ λ€λ₯Έ λλ€λ‘ λ©μλμ λμμ ν μ€νΈν μ μλ€. μλ₯Ό λ€μ΄ νλ λμΌμ΄νΈλ‘ λ§λ filter λ©μλλ₯Ό ν μ€νΈν μ μλ€.
1
2
3
4
5
6
7
8
@Test
public void testFilter() throws Exception {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
List<Integer> even = filter(numbers, i -> i % 2 == 0);
List<Integer> smallerThanThree = filter(numbers, i -> i < 3);
assertEquals(Arrays.asList(2, 4), even);
assertEquals(Arrays.asList(1, 2), smallerThanThree);
}
ν μ€νΈν΄μΌ ν λ©μλκ° λ€λ₯Έ ν¨μλ₯Ό λ°ννλ€λ©΄ μ΄λ»κ² ν΄μΌ ν κΉ? μ΄λλ Comparatorμμ μ΄ν΄λ΄€λ κ²μ²λΌ ν¨μν μΈν°νμ΄μ€μ μΈμ€ν΄μ€λ‘ κ°μ£Όνκ³ ν¨μμ λμμ ν μ€νΈν μ μλ€.
9.4 λλ²κΉ
λ¬Έμ κ° λ°μν μ½λλ₯Ό λλ²κΉ ν λ κ°λ°μλ λ€μ λ κ°μ§λ₯Ό κ°μ₯ λ¨Όμ νμΈν΄μΌ νλ€.
- μ€ν νΈλ μ΄μ€
- λ‘κΉ
νμ§λ§ λλ€ ννμκ³Ό μ€νΈλ¦Όμ κΈ°μ‘΄μ λλ²κΉ κΈ°λ²μ 무λ ₯ννλ€.
9.4.1 μ€ν νΈλ μ΄μ€ νμΈ
μλ₯Ό λ€μ΄ μμΈ λ°μμΌλ‘ νλ‘κ·Έλ¨ μ€νμ΄ κ°μκΈ° μ€λ¨λμλ€λ©΄ λ¨Όμ μ΄λμμ λ©μ·κ³ μ΄λ»κ² λ©μΆκ² λμλμ§ μ΄ν΄λ΄μΌ νλ€. λ°λ‘ μ€ν νλ μμμ μ΄ μ 보λ₯Ό μ»μ μ μλ€.
νλ‘κ·Έλ¨μ΄ λ©μλλ₯Ό νΈμΆν λλ§λ€ νλ‘κ·Έλ¨μμμ νΈμΆ μμΉ, νΈμΆν λμ μΈμκ°, νΈμΆλ λ©μλμ μ§μ λ³μ λ±μ ν¬ν¨ν νΈμΆ μ λ³΄κ° μμ±λλ©° μ΄λ€ μ 보λ μ€ν νλ μμ μ μ₯λλ€.
λ°λΌμ νλ‘κ·Έλ¨μ΄ λ©μ·λ€λ©΄ νλ‘κ·Έλ¨μ΄ μ΄λ»κ² λ©μΆκ² λμλμ§ νλ μλ³λ‘ 보μ¬μ£Όλ μ€ν νΈλ μ΄μ€λ₯Ό μ»μ μ μλ€. μ¦, λ¬Έμ κ° λ°μν μ§μ μ μ΄λ₯΄κ² λ λ©μλ νΈμΆ 리μ€νΈλ₯Ό μ»μ μ μλ€.
λλ€μ μ€ν νΈλ μ΄μ€
λλ€ ννμμ μ΄λ¦μ΄ μκΈ° λλ¬Έμ μ‘°κΈ λ³΅μ‘ν μ€ν νΈλ μ΄μ€κ° μμ±λλ€.
λ€μμ κ³ μμ μΌλ‘ λ¬Έμ λ₯Ό μΌμΌν€λλ‘ κ΅¬νν μ½λλ€.
1
2
3
4
5
6
7
8
import java.util.*;
public class Debugging {
public static void main(String[] args) {
List<Point> points = Arrays.asList(new Point(12, 2), null);
points.stream().map(p -> p.getX()).forEach(System.out::println);
}
}
νλ‘κ·Έλ¨μ μ€ννλ©΄ λ€μκ³Ό κ°μ μ€ν νΈλ μ΄μ€κ° μΆλ ₯λλ€.
1
2
3
4
5
6
Exception in thread "main" java.lang.NullPointerExceptino
at Debugging.lambda$main$0(Debugging.java:6) //$0μ λ¬΄μ¨ μλ―ΈμΈκ°?
at Debugging$$Lambda$5/284720968.apply(Unknown Source)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
...
μλνλ λλ‘ points 리μ€νΈμ λμ§Έ μΈμκ° nullμ΄λ―λ‘ νλ‘κ·Έλ¨μ μ€νμ΄ λ©μ·λ€.
μ€νΈλ¦Ό νμ΄νλΌμΈμμ μλ¬κ° λ°μνμΌλ―λ‘ μ€νΈλ¦Ό νμ΄νλΌμΈ μμ κ³Ό κ΄λ ¨λ μ 체 λ©μλ νΈμΆ 리μ€νΈκ° μΆλ ₯λμλ€. λ©μλ νΈμΆ 리μ€νΈμ λ€μμ²λΌ μμκ»λΌ κ°μ μ 보λ ν¬ν¨λμ΄ μλ€.
1
2
at Debugging.lambda$main$0(Debugging.java:6)
at Debugging$$Lambda$5/284720968.apply(Unknown Source)
μ΄μ κ°μ μ΄μν λ¬Έμλ λλ€ ννμ λ΄λΆμμ μλ¬κ° λ°μνμμ κ°λ¦¬ν¨λ€.
λλ€ ννμμ μ΄λ¦μ΄ μμΌλ―λ‘ μ»΄νμΌλ¬κ° λλ€λ₯Ό μ°Έμ‘°νλ μ΄λ¦μ λ§λ€μ΄λΈ κ²μ΄λ€.
λ©μλ μ°Έμ‘°λ₯Ό μ¬μ©ν΄λ μ€ν νΈλ μ΄μ€μλ λ©μλλͺ μ΄ λνλμ§ μλλ€. κΈ°μ‘΄μΌμ΄ λλ€ ννμ p β p.getX() λ©μλ μ°Έμ‘° Point::getXλ‘ κ³ μ³λ μ¬μ ν μ€ν νΈλ μ΄μ€λ‘λ μ΄μν μ λ³΄κ° μΆλ ₯λλ€.
1
points.stream().map(Point::getX).forEach(System.out::println);
1
2
3
4
Exception in thread "main" java.lang.NullPointerException
at Debugging$$Lambda$5/284720968.apply(Unknown Source)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
...
λ©μλ μ°Έμ‘°λ₯Ό μ¬μ©νλ ν΄λμ€μ κ°μ κ³³μ μ μΈλμ΄ μλ λ©μλλ₯Ό μ°Έμ‘°ν λλ λ©μλ μ°Έμ‘° μ΄λ¦μ΄ μ€ν νΈλ μ΄μμ λνλλ€.
1
2
3
4
5
6
7
8
9
10
11
12
import java.util.*;
public class Debugging {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3);
numbers.stream().map(Debugging::divideByZero).forEach(System.out::println);
}
// λ©μλ μ°Έμ‘°λ₯Ό μ¬μ©νλ ν΄λμ€(Debugging)κ³Ό κ°μ κ³³μ μ μΈλμ΄ μλ λ©μλ
public static int divideByZero(int n) {
return n / 0;
}
}
divideByZero λ©μλλ μ€ν νΈλ μ΄μ€μ μ λλ‘ νμλλ€.
1
2
3
4
5
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Debugging.**divideByZero**(Debugging.java:10) // μ€ν νΈλ μ΄μ€μ divideByZeroκ° λ³΄μΈλ€.
at Debugging.$$Lambda$1/999966131.apply(Unknown Source)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
...
9.4.2 μ 보 λ‘κΉ
μ€νΈλ¦Όμ νμ΄νλΌμΈ μ°μ°μ λλ²κΉ νλ€κ³ κ°μ νμ λ, λ€μμ²λΌ forEachλ‘ μ€νΈλ¦Ό κ²°κ³ λ₯Ό μΆλ ₯νκ±°λ λ‘κΉ ν μ μλ€.
1
2
3
4
5
6
List<Integer> numbers = Arrays.asList(2, 3, 4, 5);
numbers.stream()
.map(x -> x + 17)
.filter(x -> x % 2 == 0)
.limit(3)
.forEach(System.out::println);
λ€μμ νλ‘κ·Έλ¨ μΆλ ₯ κ²°κ³Όλ€.
1
2
20
22
μνκΉκ²λ forEachλ₯Ό νΈμΆνλ μκ° μ 체 μ€νΈλ¦Όμ΄ μλΉλλ€. μ€νΈλ¦Ό νμ΄νλΌμΈμ μ μ©λ κ°κ°μ μ°μ°(map, filter, limit)μ΄ μ΄λ€ κ²°κ³Όλ₯Ό λμΆνλμ§ νμΈν μ μλ€λ©΄ μ’μ κ²μ΄λ€.
μ΄λ peekμ΄λΌλ μ€νΈλ¦Ό μ°μ°μ νμ©ν μ μλ€. peekμ μ€νΈλ¦Όμ κ° μμλ₯Ό μλΉν κ²μ²λΌ λμμ μ€ννλ€. νμ§λ§ forEachμ²λΌ μ€μ λ‘ μ€νΈλ¦Όμ μμλ₯Ό μλΉνμ§λ μλλ€.
peekμ μμ μ΄ νμΈν μμλ₯Ό νμ΄νλΌμΈμ λ€μ μ°μ°μΌλ‘ κ·Έλλ‘ μ λ¬νλ€.
λ€μ μ½λμμλ peekμΌλ‘ μ€νΈλ¦Ό νμ΄νλΌμΈμ κ° λμ μ νμ μ€κ°κ°μ μΆλ ₯νλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
List<Integer> result =
numbers.stream()
// μμ€μμ μ²μ μλΉν μμλ₯Ό μΆλ ₯νλ€.
.peek(x -> System.out.println("from stream: " + x))
.map(x -> x + 17)
// map λμ μ€ν κ²°κ³Όλ₯Ό μΆλ ₯νλ€.
.peek(x -> System.out.println("after map: " + x))
.filter(x -> x % 2 == 0)
// filter λμ ν μ νλ μ«μλ₯Ό μΆλ ₯νλ€.
.peek(x -> Systeml.out.println("after filter: " + x))
.limit(3)
// limit λμ ν μ νλ μ«μλ₯Ό μΆλ ₯νλ€.
.peek(x -> System.out.println("after limit: " + x))
.collect(toList());
λ€μμ νμ΄νλΌμΈμ κ° λ¨κ³λ³ μνλ₯Ό 보μ¬μ€λ€.
1
2
3
4
5
6
7
8
9
10
11
from stream: 2
after map: 19
from stream: 3
after map: 20
after filter: 20
from stream: 4
after map: 21
from stream: 5
after map: 22
after filter: 22
after limit: 22