
package me.whiteship.chapter07.item45.anagram;
import java.io.File;
import java.io.IOException;
import java.util.*;
// 코드 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);
}
}
package me.whiteship.chapter07.item45.anagram;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
import static java.util.stream.Collectors.groupingBy;
// 코드 45-2 스트림을 과하게 사용했다. - 따라 하지 말 것! (270-271쪽)
public class StreamAnagrams {
public static void main(String[] args) throws IOException {
Path dictionary = Paths.get(args[0]);
int minGroupSize = Integer.parseInt(args[1]);
try (Stream<String> words = Files.lines(dictionary)) {
words.collect(
groupingBy(word -> word.chars().sorted()
.collect(StringBuilder::new,
(sb, c) -> sb.append((char) c),
StringBuilder::append).toString()))
.values().stream()
.filter(group -> group.size() >= minGroupSize)
.map(group -> group.size() + ": " + group)
.forEach(System.out::println);
}
}
}
너무 복잡해진다.
package me.whiteship.chapter07.item45.anagram;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.stream.Stream;
import static java.util.stream.Collectors.groupingBy;
// 코드 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);
}
}
이렇게 하면 적절하게 사용할 수 있다.
중간 연산(intermediate operations) 과 종단 연산(terminal operation)

https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html
return 타입이 Stream<T>면 중간 연산이다.
return이 static Stream이면 Stream 자체를 만들어주는 경우
Stream이 아니면 종단인거다.

package me.whiteship.chapter07.item45;
import java.math.BigInteger;
import java.util.stream.Stream;
import static java.math.BigInteger.ONE;
import static java.math.BigInteger.TWO;
// 스트림을 사용해 처음 20개의 메르센 소수를 생성한다. (274쪽)
public class MersennePrimes {
static Stream<BigInteger> primes() {
return Stream.iterate(TWO, BigInteger::nextProbablePrime);
}
public static void main(String[] args) {
primes().map(p -> TWO.pow(p.intValueExact()).subtract(ONE))
.filter(mersenne -> mersenne.isProbablePrime(50))
.limit(20)
.forEach(mp -> System.out.println(mp.bitLength() + ": " + mp));
}
}
package me.whiteship.chapter07.item45;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toList;
// 반복 방식과 스트림 방식으로 두 리스트의 데카르트 곱을 생성한다. (275-276쪽)
public class Card {
public enum Suit { SPADE, HEART, DIAMOND, CLUB }
public enum Rank { ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN,
EIGHT, NINE, TEN, JACK, QUEEN, KING }
private final Suit suit;
private final Rank rank;
@Override public String toString() {
return rank + " of " + suit + "S";
}
public Card(Suit suit, Rank rank) {
this.suit = suit;
this.rank = rank;
}
private static final List<Card> NEW_DECK = newDeck();
// 코드 45-4 데카르트 곱 계산을 반복 방식으로 구현 (275쪽)
private static List<Card> newDeck() {
List<Card> result = new ArrayList<>();
for (Suit suit : Suit.values())
for (Rank rank : Rank.values())
result.add(new Card(suit, rank));
return result;
}
// 코드 45-5 데카르트 곱 계산을 스트림 방식으로 구현 (276쪽)
// private static List<Card> newDeck() {
// return Stream.of(Suit.values())
// .flatMap(suit ->
// Stream.of(Rank.values())
// .map(rank -> new Card(suit, rank)))
// .collect(toList());
// }
public static void main(String[] args) {
System.out.println(NEW_DECK);
}
}
package me.whiteship.chapter07.item45;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toList;
// 반복 방식과 스트림 방식으로 두 리스트의 데카르트 곱을 생성한다. (275-276쪽)
public class Card {
public enum Suit { SPADE, HEART, DIAMOND, CLUB }
public enum Rank { ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN,
EIGHT, NINE, TEN, JACK, QUEEN, KING }
private final Suit suit;
private final Rank rank;
@Override public String toString() {
return rank + " of " + suit + "S";
}
public Card(Suit suit, Rank rank) {
this.suit = suit;
this.rank = rank;
}
private static final List<Card> NEW_DECK = newDeck();
// 코드 45-4 데카르트 곱 계산을 반복 방식으로 구현 (275쪽)
// private static List<Card> newDeck() {
// List<Card> result = new ArrayList<>();
// for (Suit suit : Suit.values())
// for (Rank rank : Rank.values())
// result.add(new Card(suit, rank));
// return result;
// }
// 코드 45-5 데카르트 곱 계산을 스트림 방식으로 구현 (276쪽)
private static List<Card> newDeck() {
return Stream.of(Suit.values())
.flatMap(suit ->
Stream.of(Rank.values())
.map(rank -> new Card(suit, rank)))
.collect(toList());
}
public static void main(String[] args) {
System.out.println(NEW_DECK);
}
}
stream으로 변경 가능하다.
map으로 string을 받앗다가 int로 바꾸려고 하면 계속 int로 된다.
package me.whiteship.chapter07.item45;
// char 데이터를 처리할 때는 스트림 사용을 자제하자. (272쪽)
public class CharStream {
public static void main(String[] args) {
// 예상한 결과와 다르다.
"Hello world!".chars().forEach(System.out::print);
System.out.println();
// 문제를 고치려면 형변환을 명시적으로 해줘야 한다.
"Hello world!".chars().forEach(x -> System.out.print((char) x));
System.out.println();
}
}
형변환을 해줘야 해서 성능이 악화될 수도 있다.