스트림: 데이터 원소의 유한 혹은 무한 시퀀스
스트림 파이프라인: 원소들로 수행하는 연산 단계

지연 평가: 종단 연산이 없는 스트림은 아무 일도 하지 않는다. 종단 연산이 호출 될 때 스트림을 처리한다.
플루언트 API: 모든 연산(호출)을 연결하여 단 하나의 표현식을 완성할 수 있다.
Before
// 코드 45-1 사전 하나를 훑어 원소 수가 많은 아나그램 그룹들을 출력한다. (269-270쪽)
// 메서드를 각 분리해서 스트림을 쓰지 않아도 좋음
public class IterativeAnagrams {
public static void main(String[] args) throws IOException {
File dictionary = new File(args[0]);
int minGroupSize = Integer.parseInt(args[1]);
// cat, tac => act, act => cat, tac
Map<String, Set<String>> groups = new HashMap<>();
try (Scanner s = new Scanner(dictionary)) {
while (s.hasNext()) {
String word = s.next();
groups.computeIfAbsent(alphabetize(word),
(unused) -> new TreeSet<>()).add(word);
}
}
for (Set<String> group : groups.values())
if (group.size() >= minGroupSize)
System.out.println(group.size() + ": " + group);
}
private static String alphabetize(String s) {
char[] a = s.toCharArray();
Arrays.sort(a);
return new String(a);
}
}
After
// 코드 45-3 스트림을 적절히 활용하면 깔끔하고 명료해진다. (271쪽)
public class HybridAnagrams {
public static void main(String[] args) throws IOException {
Path dictionary = Paths.get(args[0]);
int minGroupSize = Integer.parseInt(args[1]);
// act => cat, tac
try (Stream<String> words = Files.lines(dictionary)) {
words.collect(groupingBy(word -> alphabetize(word)))
.values().stream()
.filter(group -> group.size() >= minGroupSize)
.forEach(g -> System.out.println(g.size() + ": " + g));
}
}
private static String alphabetize(String s) {
char[] a = s.toCharArray();
Arrays.sort(a);
return new String(a);
}
}
중간 연산
• filter, map, sorted, distinct, limit, flatMap, skip, … • 스트림에 들어있는 원소를 거르거나, 변경하거나, 정렬한다.
종단 연산