-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathIterableDemo.java
More file actions
163 lines (144 loc) · 5.99 KB
/
Copy pathIterableDemo.java
File metadata and controls
163 lines (144 loc) · 5.99 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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package Phase5_CollectionsLambdasStreams.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Spliterator;
/**
* java.lang.Iterable<T> - The "for-each" Contract
* -----------------------------------------------
* Any class that implements Iterable can be used in Java's enhanced
* for-each loop:
* <p>
*
* for (Item i : container) { ... }
* <p>
*
* The compiler rewrites that loop to call iterator() on `container` and
* then drive it. Implementing Iterable is therefore the simplest way to
* make your own class loopable.
* <p>
*
* The Iterable Contract (Java 8+)
* -------------------------------
* Iterator<T> iterator() [required]
* default void forEach(Consumer<? super T>) [added in Java 8]
* default Spliterator<T> spliterator() [added in Java 8]
* <p>
*
* The two defaults give every Iterable a forEach(...) and stream()
* (indirectly through spliterator) for free.
* <p>
*
* Relationship to Other Types
* ---------------------------
* Iterable<T> <-- root
* |
* v
* Collection<T> - List, Set, Queue, Deque
* Path, FileChannel.LinesStream, ... - various other types
* <p>
*
* Why Implement Iterable?
* -----------------------
* - Domain objects with collection-like behaviour ("matrix rows",
* "events in a session") become loopable.
* - Stream support follows automatically with
* StreamSupport.stream(it.spliterator(), false).
* - Any user of your type can stop caring whether you store data in an
* ArrayList, a database cursor, or a generator.
* <p>
*
* Two Custom Iterables Below
* --------------------------
* IntRange - generates 0..n-1 lazily; no backing storage.
* LinkedChain - tiny linked list, with its own Iterator implementation.
*/
public class IterableDemo {
// ============================================================
// 1) IntRange - "for (int i : new IntRange(5))"
// ============================================================
static class IntRange implements Iterable<Integer> {
private final int fromIncl, toExcl;
IntRange(int fromIncl, int toExcl) {
if (fromIncl > toExcl) throw new IllegalArgumentException("from > to");
this.fromIncl = fromIncl;
this.toExcl = toExcl;
}
@Override public Iterator<Integer> iterator() {
return new Iterator<>() {
int cursor = fromIncl;
@Override public boolean hasNext() { return cursor < toExcl; }
@Override public Integer next() {
if (!hasNext()) throw new NoSuchElementException();
return cursor++;
}
};
}
}
// ============================================================
// 2) LinkedChain - a minimal linked list that is Iterable
// ============================================================
static class LinkedChain<E> implements Iterable<E> {
private Node<E> head;
public LinkedChain<E> add(E v) {
if (head == null) { head = new Node<>(v); }
else {
Node<E> cur = head;
while (cur.next != null) cur = cur.next;
cur.next = new Node<>(v);
}
return this;
}
@Override public Iterator<E> iterator() {
return new Iterator<>() {
Node<E> cur = head;
@Override public boolean hasNext() { return cur != null; }
@Override public E next() {
if (cur == null) throw new NoSuchElementException();
E v = cur.value;
cur = cur.next;
return v;
}
};
}
private static class Node<E> {
E value; Node<E> next;
Node(E v) { this.value = v; }
}
}
public static void main(String[] args) {
section("1) Use the IntRange in a for-each loop");
for (int n : new IntRange(0, 5)) System.out.print(n + " ");
System.out.println();
section("2) Use the IntRange with forEach (default method - free)");
new IntRange(10, 14).forEach(n -> System.out.println(" forEach " + n));
section("3) Iterable.spliterator gives you Stream support for free");
long evens = java.util.stream.StreamSupport
.stream(new IntRange(0, 10).spliterator(), /*parallel*/ false)
.filter(n -> n % 2 == 0)
.count();
System.out.println("evens in 0..9 = " + evens);
section("4) LinkedChain - your own linked list, fully loopable");
LinkedChain<String> chain = new LinkedChain<>();
chain.add("alpha").add("beta").add("gamma");
for (String s : chain) System.out.println(" " + s);
// forEach + spliterator work here too because Iterable supplies them.
section("5) Iterable is the bridge - everything in java.util uses it");
Iterable<Integer> list = List.of(1, 2, 3); // List implements Iterable
Iterable<Integer> set = new java.util.HashSet<>(List.of(4, 5, 6));
Iterable<Integer> q = new java.util.ArrayDeque<>(List.of(7, 8, 9));
for (Iterable<Integer> it : List.of(list, set, q)) {
System.out.print("iter: "); it.forEach(n -> System.out.print(n + " "));
System.out.println();
}
section("6) Spliterator characteristics (informational)");
Spliterator<Integer> sp = new IntRange(0, 4).spliterator();
System.out.println("estimateSize() = " + sp.estimateSize());
// Our quick implementation uses the default Iterable.spliterator, which
// does NOT know an exact size; it returns Long.MAX_VALUE for that.
// OUTPUT (representative)
}
private static void section(String title) {
System.out.println("\n====== " + title + " ======");
}
}