-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathExample156.java
More file actions
137 lines (115 loc) · 5.86 KB
/
Example156.java
File metadata and controls
137 lines (115 loc) · 5.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Example 156 from page 127
//
import java.util.function.Function;
import java.util.function.IntSupplier;
import java.util.function.LongFunction;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;
import java.math.BigInteger;
// Convert a long integer between -999_999_999_999 and
// +999_999_999_999 to an English numeral.
// For instance, Integer.MIN_VALUE is minus two billion one hundred
// forty-seven million four hundred eighty-three thousand six hundred
// forty-eight
class Example156 {
public static void main(String[] args) {
System.out.printf("Integer.MAX_VALUE = %s%n%n", toEnglish(Integer.MAX_VALUE));
System.out.printf("Integer.MIN_VALUE = %s%n%n", toEnglish(Integer.MIN_VALUE));
System.out.println("The Fibonacci numbers:");
infiniteFibonacciStream();
// The infinite stream of numerals "zero", "one", "two", "three", ...
Stream<String> numerals
= LongStream.iterate(0, x -> x+1).mapToObj(Example156::toEnglish);
// numerals.forEach(System.out::println);
// The infinite stream of logorithms 4, 3, 3, 5, ...
IntStream logorithms = numerals.mapToInt(String::length);
// logorithms.forEach(i -> System.out.printf("%d ", i));
System.out.println();
System.out.println("The maximal logorithm of n <= 1_000_000 is:");
System.out.println(logorithms.limit(1_000_000).max());
System.out.println("\nFive ways to compose Example156::toEnglish and String::length:");
int enough = 35;
Supplier<Stream<Long>> nats = () -> LongStream.range(1, enough).boxed();
nats.get().map(Example156::toEnglish).map(String::length).forEach(x -> System.out.printf("%d ", x));
System.out.println();
// Illegal: The method reference expression Example156::toEnglish
// must appear in assignment context, invocation context, or
// casting context:
// nats.get().map(Example156::toEnglish.andThen(x -> length(x))).forEach(x -> System.out.printf("%d ", x));
traverse1(nats.get(), Example156::toEnglish, String::length).forEach(x -> System.out.printf("%d ", x));
System.out.println();
traverse2(nats.get(), Example156::toEnglish, String::length).forEach(x -> System.out.printf("%d ", x));
System.out.println();
traverse3(nats.get(), Example156::toEnglish, String::length).forEach(x -> System.out.printf("%d ", x));
System.out.println();
wildcardDemo();
}
// ----------------------------------------------------------------------
// Converting a long to the corresponding English numeral:
private static final String[]
ones = { "", "one", "two", "three", "four", "five", "six", "seven", "eight",
"nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
"sixteen", "seventeen", "eighteen", "nineteen" },
tens = { "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };
private static String less100(long n) {
return n<20 ? ones[(int)n] : tens[(int)n/10-2] + after("-", ones[(int)n%10]);
}
// Preconditions: n < limit * limit, and conv.apply(i) works for all i < limit
private static LongFunction<String> less(long limit, String unit, LongFunction<String> conv) {
return n -> n<limit ? conv.apply(n)
: conv.apply(n/limit) + " " + unit + after(" ", conv.apply(n%limit));
}
private static String after(String d, String s) { return s.equals("") ? "" : d + s; }
private static final LongFunction<String>
less1K = less( 100, "hundred", Example156::less100),
less1M = less( 1_000, "thousand", less1K),
less1B = less( 1_000_000, "million", less1M),
less1G = less(1_000_000_000, "billion", less1B);
public static String toEnglish(long n) {
return n==0 ? "zero" : n<0 ? "minus " + less1G.apply(-n) : less1G.apply(n);
}
// Hand-fusion of traversals
public static <T,U,V> Stream<V> traverse1(Stream<T> xs, Function<T,U> f, Function<U,V> g) {
return xs.map(f).map(g);
}
public static <T,U,V> Stream<V> traverse2(Stream<T> xs, Function<T,U> f, Function<U,V> g) {
return xs.map(f.andThen(g));
}
public static <T,U,V> Stream<V> traverse3(Stream<T> xs,
Function<? super T, ? extends U> f,
Function<? super U, ? extends V> g) {
return xs.map(f.andThen(g));
}
// The utility of wildcard types
public static void wildcardDemo() {
int enough = 35;
Stream<Long> nats = LongStream.range(1, enough).boxed();
Function<Number,String> toEnglish = (Number n) -> toEnglish((long)n);
Function<Object,Integer> length = (Object o) -> ((String)o).length();
// Stream<Double> res = traverse2(nats, toEnglish, length); // Type error!
Stream<Integer> res = traverse3(nats, toEnglish, length);
res.forEach(x -> System.out.printf("%d ", x));
System.out.println();
}
public static void infiniteIntStreams() {
IntStream nats1 = IntStream.iterate(0, x -> x+1);
IntStream nats2 = IntStream.generate(new IntSupplier() {
private int next = 0;
public int getAsInt() { return next++; }
});
final int[] next = { 0 }; // next is final, its element mutable by the lambda
IntStream nats3 = IntStream.generate(() -> next[0]++);
nats3.forEach(i -> System.out.printf("%d ", i));
}
public static void infiniteFibonacciStream() {
final BigInteger[] fib = { BigInteger.ZERO, BigInteger.ONE }; // fib is final, its elements mutable
Stream<BigInteger> fibonaccis =
Stream.generate(() -> { BigInteger f1=fib[1]; fib[1]=fib[0].add(fib[1]); return fib[0]=f1; });
// Can generate very large Fibonacci numbers:
// fibonaccis.forEach(System.out::println);
// The Fibonacci numbers below 1 trillion, in English:
fibonaccis.limit(59).map(b -> toEnglish(b.longValue())).forEach(System.out::println);
}
}