-
Notifications
You must be signed in to change notification settings - Fork 90
/
ch12.html
715 lines (446 loc) · 45.1 KB
/
ch12.html
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Study guide for the Oracle Certified Professional, Java SE 8 Programmer Exam ">
<title>Java 8 Programmer II Study Guide: Exam 1Z0-809</title>
<link href="css/code.css" rel="stylesheet" type="text/css" />
<link href="css/style.css" rel="stylesheet" type="text/css" />
<link href="https://netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script src="js/common-sections.js"></script>
</head>
<body>
<div class="nav"></div>
<div class="header">
<div class="title-container">
<div class="chapter-title">
<h1><i class="chapter">Part FOUR</i><br />
Streams and Collections</h1>
<h1><i class="chapter">Chapter TWELVE</i><br />
Streams</h1>
<p><br /></p>
<h3 style="text-align: center;"><i>Exam Objectives</i></h3>
<p style="text-align: center;"><i>Describe Stream interface and Stream pipeline.<br /></i><i>Use method references with Streams.</i></p>
</div>
</div>
</div>
<div class="container">
<div class="column">
<h2>A simple example</h2>
<p>Suppose you have a list of students and the requirements are to extract the students with a score of <code>90.0</code> or greater and sort them by score in ascending order.</p>
<p>One way to do it would be:</p>
<p><code class="java hljs">List<Student> studentsScore = <span class="hljs-keyword">new</span> ArrayList<Student>();<br />
<span class="hljs-keyword">for</span>(Student s : students) {<br />
<span class="hljs-keyword"> if</span>(s.getScore() >= <span class="hljs-number">90.0</span>) {<br />
studentsScore.add(s);<br />
}<br />
}<br />
Collections.sort(studentsScore, <span class="hljs-keyword">new</span> Comparator<Student>() {<br />
<span class="hljs-function"><span class="hljs-keyword"> public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">compare</span><span class="hljs-params">(Student s1, Student s2)</span></span> {<br />
<span class="hljs-keyword"><font color="#000000"> </font>return</span> Double.compare(<br />
s1.getScore(), s2.getScore());<br />
}<br />
});</code></p>
<p>Very verbose when we compare it with the Java 8 implementation using streams:</p>
<p><code class="java hljs">List<Student> studentsScore = students<br />
.stream()<br />
.filter(s -> s.getScore() >= <span class="hljs-number">90.0</span>)<br />
.sorted(Comparator.comparing(Student::getScore))<br />
.collect(Collectors.toList());</code></p>
<p>Don't worry if you don't fully understand the code; we'll see what it means later.</p>
<h2>What are streams?</h2>
<p>First, streams are <b>NOT</b> collections.</p>
<p>A simple definition is that streams are <b>WRAPPERS</b> for collections and arrays. They wrap an <b>EXISTING</b> collection (or another data source) to support operations expressed with <b>LAMBDAS</b>, so you specify what you want to do, not how to do it. You already saw it.</p>
<p>These are the characteristics of a stream:</p>
<p><b>Streams work perfectly with lambdas.</b><br /> All streams operations take functional interfaces as arguments, so you can simplify the code with lambda expressions (and method references).</p>
<p><b>Streams don't store its elements.</b><br /> The elements are stored in a collection or generated on the fly. They are only carried from the source through a pipeline of operations.</p>
<p><b>Streams are immutable.</b><br /> Streams don't mutate their underlying source of elements. If, for example, an element is removed from the stream, a new stream with this element removed is created.</p>
<p><b>Streams are not reusable.</b><br /> Streams can be traversed only once. After a terminal operation is executed (we'll see what this means in a moment), you have to create another stream from the source to further process it.</p>
<p><b>Streams don't support indexed access to their elements.</b><br /> Again, streams are not collections or arrays. The most you can do is get their first element.</p>
<p><b>Streams are easily parallelizable.</b><br /> With the call of a method (and following certain rules), you can make a stream execute its operations concurrently, without having to write any multithreading code.</p>
<p><b>Stream operations are lazy when possible.</b><br /> Streams defer the execution of their operations either until the results are needed or until it's known how much data is needed.</p>
<p>One thing that allows this laziness is the way their operations are designed. Most of them return a new stream, allowing operations to be chained and form a pipeline that enables this kind of optimizations.</p>
<p>To set up this pipeline you:</p>
<ol>
<li>Create the stream.</li>
<li>Apply zero or more intermediate operations to transform the initial stream into new streams.</li>
<li>Apply a terminal operation to generate a result or a "side-effect".</li>
</ol>
<p>We're going to explain these steps and finally, we'll talk about more about laziness. In subsequent chapters, we'll go through all the operations supported by streams.</p>
<h2>Creating streams</h2>
<p>A stream is represented by the <code>java.util.stream.Stream<T></code> interface. This works with objects only.</p>
<p>There are also specializations to work with primitive types, such as <code>IntStream</code>, <code>LongStream</code>, and <code>DoubleStream</code>.</p>
<p>There are many ways to create a stream. Let's start with the most popular three.</p>
<p>The first one is creating a stream from a <code>java.util.Collection</code> implementation using the <code>stream()</code> method:</p>
<p><code class="java hljs">List<String> words = Arrays.asList(<span class="hljs-keyword">new</span> String[]{<span class="hljs-string">"hello"</span>, <span class="hljs-string">"hola"</span>, <span class="hljs-string">"hallo"</span>, <span class="hljs-string">"ciao"</span>});<br />
Stream<String> stream = words.stream();</code></p>
<p>The second one is creating a stream from individual values:</p>
<p><code class="java hljs">Stream<String> stream = Stream.of(<span class="hljs-string">"hello"</span>,<span class="hljs-string">"hola"</span>, <span class="hljs-string">"hallo"</span>, <span class="hljs-string">"ciao"</span>);</code></p>
<p>The third one is creating a stream from an array:</p>
<p><code class="java hljs">String[] words = {<span class="hljs-string">"hello"</span>, <span class="hljs-string">"hola"</span>, <span class="hljs-string">"hallo"</span>, <span class="hljs-string">"ciao"</span>};<br />
Stream<String> stream = Stream.of(words);</code></p>
<p>However, you have to be careful with this last method when working with primitives.</p>
<p>Here's why. Assume an <code>int</code> array:</p>
<p><code class="java hljs"><span class="hljs-keyword">int</span>[] nums = {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>};</code></p>
<p>When we create a stream from this array like this:</p>
<p><code class="java hljs">Stream.of(nums)</code></p>
<p>We are not creating a stream of <code>Integer</code>s (<code>Stream<Integer></code>), but a stream of <code>int</code> arrays (<code>Stream<int[]></code>). This means that instead of having a stream with five elements we have a stream of one element:</p>
<p><code class="java hljs">System.out.println(Stream.of(nums).count()); <span class="hljs-comment">// It prints 1!</span></code></p>
<p>The reason is the signatures of the of method:</p>
<p><code class="java hljs"><span class="hljs-comment">// returns a stream of one element</span><br />
<span class="hljs-keyword">static</span> <T> <span class="hljs-function">Stream<T> <span class="hljs-title">of</span><span class="hljs-params">(T t)<br /></span><span class="hljs-comment">// returns a stream whose elements are the specified values</span><br />
<span class="hljs-keyword">static</span> <T> Stream<T> <span class="hljs-title">of</span><span class="hljs-params">(T... values)</span></span></code></p>
<p>Since an int is not an object, but <code>int[]</code> is, the method chosen to create the stream is the first (<code>Stream.of(T t)</code>), not the one with the vargs, so a stream of <code>int[]</code> is created, but since only one array is passed, the result is a stream of one element.</p>
<p>To solve this, we can force Java to choose the vargs version by creating an array of objects (with <code>Integer</code>):</p>
<p><code class="java hljs">Integer[] nums = {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>};<br />
<span class="hljs-comment">// It prints 5!<br /></span>System.out.println(Stream.of(nums).count());</code></p>
<p>Or use a fourth way to create a stream (that it's in fact used inside <code>Stream.of(T... values)</code>):</p>
<p><code class="java hljs"><span class="hljs-keyword">int</span>[] nums = {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>};<br />
<span class="hljs-comment">// It also prints 5!<br /></span>System.out.println(Arrays.stream(nums).count());</code></p>
<p>Or use the primitive version <code>IntStream</code>:</p>
<p><code class="java hljs"><span class="hljs-keyword">int</span>[] nums = {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>};<br />
<span class="hljs-comment">// It also prints 5!<br /></span>System.out.println(IntStream.of(nums).count());</code></p>
<p>Lesson learned: Don't use <code>Stream<T>.of()</code> when working with primitives.</p>
<p>Here are other ways to create streams.</p>
<p><code class="java hljs"><span class="hljs-keyword">static</span> <T> <span class="hljs-function">Stream<T> <span class="hljs-title">generate</span><span class="hljs-params">(Supplier<T> s)</span></span></code></p>
<p>This method returns an "infinite" stream where each element is generated by the provided <code>Supplier</code>, and it's generally used with the method:</p>
<p><code class="java hljs"><span class="hljs-function">Stream<T> <span class="hljs-title">limit</span><span class="hljs-params">(<span class="hljs-keyword">long</span> maxSize)</span></span></code></p>
<p>That truncates the stream to be no longer than <code>maxSize</code> in length.</p>
<p>For example:</p>
<p><code class="java hljs">Stream<Double> s = Stream.generate(<span class="hljs-keyword">new</span> Supplier<Double>() {<br />
<span class="hljs-function"><span class="hljs-keyword"> public</span> Double <span class="hljs-title">get</span><span class="hljs-params">()</span></span> {<br />
<span class="hljs-keyword"> return</span> Math.random();<br />
}<br />
}).limit(<span class="hljs-number">5</span>);</code></p>
<p>Or:</p>
<p><code class="java hljs">Stream<Double> s = Stream.generate(() -> Math.random()).limit(<span class="hljs-number">5</span>);</code></p>
<p>Or just:</p>
<p><code class="java hljs">Stream<Double> s = Stream.generate(Math::random).limit(<span class="hljs-number">5</span>);</code></p>
<p>That generates a stream of five random <code>double</code>s.</p>
<p><code class="java hljs"><span class="hljs-keyword">static</span> <T> <span class="hljs-function">Stream<T> <span class="hljs-title">iterate</span><span class="hljs-params">(T seed, UnaryOperator<T> f)</span></span></code></p>
<p>This method returns an "infinite" stream produced by the iterative application of a function <code>f</code> to an initial element seed. The first element (<code>n = 0</code>) in the stream will be the provided seed. For <code>n > 0</code>, the element at position <code>n</code> will be the result of applying the function <code>f</code> to the element at position <code>n - 1</code>. For example:</p>
<p><code class="java hljs">Stream<Integer> s = Stream.iterate(<span class="hljs-number">1</span>, <span class="hljs-keyword">new</span> UnaryOperator<Integer>() {<br />
<span class="hljs-annotation"> @Override<font color="#000000"><br /></font></span><span class="hljs-function"><span class="hljs-keyword"><font color="#000000"> </font>public</span> Integer <span class="hljs-title">apply</span><span class="hljs-params">(Integer t)</span></span> {<br />
<span class="hljs-keyword"> return</span> t * <span class="hljs-number">2</span>; }<br />
}).limit(<span class="hljs-number">5</span>);</code></p>
<p>Or just:</p>
<p><code class="java hljs">Stream<Integer> s = Stream.iterate(<span class="hljs-number">1</span>, t -> t * <span class="hljs-number">2</span>).limit(<span class="hljs-number">5</span>);</code></p>
<p>That generates the elements <code>1</code>, <code>2</code>, <code>4</code>, <code>8</code>, <code>16</code>.</p>
<p>There's a <code>Stream.Builder<T></code> class (that follows the builder design pattern) with methods that add an element to the stream being built:</p>
<p><code class="java hljs">
<span class="hljs-function">
<span class="hljs-keyword">void</span> <span class="hljs-title">accept</span><span class="hljs-params">(T t)<br /></span>
<span class="hljs-keyword">default</span> Stream.Builder<T> <span class="hljs-title">add</span><span class="hljs-params">(T t)</span>
</span>
</code></p>
<p>For example:</p>
<p><code class="java hljs">Stream.Builder<String> builder = Stream.<String>builder().add(<span class="hljs-string">"h"</span>).add(<span class="hljs-string">"e"</span>).add(<span class="hljs-string">"l"</span>).add(<span class="hljs-string">"l"</span>);<br />
builder.accept(<span class="hljs-string">"o"</span>);<br />
Stream<String> s = builder.build();</code></p>
<p><code>IntStream</code> and <code>LongStream</code> define the methods:</p>
<p><code class="java hljs">
<span class="hljs-function">
<span class="hljs-keyword">static</span> IntStream <span class="hljs-title">range</span><span class="hljs-params">(<span class="hljs-keyword">int</span> startInclusive, <span class="hljs-keyword">int</span> endExclusive)<br /></span>
<span class="hljs-keyword">static</span> IntStream <span class="hljs-title">rangeClosed</span><span class="hljs-params">(<span class="hljs-keyword">int</span> startInclusive, <span class="hljs-keyword">int</span> endInclusive)<br /></span>
<span class="hljs-keyword">static</span> LongStream <span class="hljs-title">range</span><span class="hljs-params">(<span class="hljs-keyword">long</span> startInclusive, <span class="hljs-keyword">long</span> endExclusive)<br /></span>
<span class="hljs-keyword">static</span> LongStream <span class="hljs-title">rangeClosed</span><span class="hljs-params">(<span class="hljs-keyword">long</span> startInclusive, <span class="hljs-keyword">long</span> endInclusive)</span>
</span>
</code></p>
<p>That returns a sequential stream for the range of <code>int</code> or <code>long</code> elements. For example:</p>
<p><code class="java hljs"><span class="hljs-comment">// stream of 1, 2, 3<br /></span>IntStream s = IntStream.range(<span class="hljs-number">1</span>, <span class="hljs-number">4</span>);<br />
<span class="hljs-comment">// stream of 1, 2, 3, 4<br /></span>IntStream s = IntStream.rangeClosed(<span class="hljs-number">1</span>, <span class="hljs-number">4</span>);</code></p>
<p>Also, there are new methods in the Java API that generate streams. For example:</p>
<p><code class="java hljs">IntStream s1 = <span class="hljs-keyword">new</span> Random().ints(<span class="hljs-number">5</span>, <span class="hljs-number">1</span>, <span class="hljs-number">10</span>);</code></p>
<p>That returns an <code>IntStream</code> of five random <code>int</code>s from one (inclusive) to ten (exclusive).</p>
<h2>Intermediate operations</h2>
<p>You can easily identify intermediate operations; they always return a new stream. This allows the operations to be connected.</p>
<p>For example:</p>
<p><code class="java hljs">Stream<String> s = Stream.of(<span class="hljs-string">"m"</span>, <span class="hljs-string">"k"</span>, <span class="hljs-string">"c"</span>, <span class="hljs-string">"t"</span>)<br />
.sorted()<br />
.limit(<span class="hljs-number">3</span>)</code></p>
<p>An important feature of intermediate operations is that they don't process the elements until a terminal operation is invoked, in other words, they're lazy.</p>
<p>Intermediate operations are further divided into <i>stateless</i> and <i>stateful</i> operations.</p>
<p>Stateless operations retain no state from previously elements when processing a new element so each can be processed independently of operations on other elements.</p>
<p>Stateful operations, such as distinct and sorted, may incorporate state from previously seen elements when processing new elements.</p>
<p>The following table summarizes the methods of the <code>Stream</code> interface that represent intermediate operations.</p>
<table border="1" cellspacing="5" width="98%">
<tr>
<th>Method</th>
<th>Type</th>
<th>Description</th>
</tr>
<tr>
<td style="text-align: center;"><code>Stream<T> distinct()</code></td>
<td style="text-align: center;"><span class="small">Stateful</span></td>
<td style="text-align: center;"><span class="small">Returns a stream consisting of the distinct elements.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Stream<T> filter(Predicate<? super T> predicate)</code></td>
<td style="text-align: center;"><span class="small">Stateless</span></td>
<td style="text-align: center;"><span class="small">Returns a stream of elements that match the given predicate.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code><R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)</code></td>
<td style="text-align: center;"><span class="small">Stateless</span></td>
<td style="text-align: center;"><span class="small">Returns a stream with the content produced by applying the provided mapping function to each element. There are versions for <code>int</code>, <code>long</code> and <code>double</code> also.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Stream<T> limit(long maxSize)</code></td>
<td style="text-align: center;"><span class="small">Stateful</span></td>
<td style="text-align: center;"><span class="small">Returns a stream truncated to be no longer than <code>maxSize</code> in length.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code><R> Stream<R> map(Function<? super T,? extends R> mapper)</code></td>
<td style="text-align: center;"><span class="small">Stateless</span></td>
<td style="text-align: center;"><span class="small">Returns a stream consisting of the results of applying the given function to the elements of this stream. There are versions for <code>int</code>, <code>long</code> and <code>double</code> also.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Stream<T> peek(Consumer<? super T> action)</code></td>
<td style="text-align: center;"><span class="small">Stateless</span></td>
<td style="text-align: center;"><span class="small">Returns a stream with the elements of this stream, performing the provided action on each element.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Stream<T> skip(long n)</code></td>
<td style="text-align: center;"><span class="small">Stateful</span></td>
<td style="text-align: center;"><span class="small">Returns a stream with the remaining elements of this stream after discarding the first n elements.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Stream<T> sorted()</code></td>
<td style="text-align: center;"><span class="small">Stateful</span></td>
<td style="text-align: center;"><span class="small">Returns a stream sorted according to the natural order of its elements.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Stream<T> sorted(Comparator<? super T> comparator)</code></td>
<td style="text-align: center;"><span class="small">Stateful</span></td>
<td style="text-align: center;"><span class="small">Returns a stream sorted according to the provided <code>Comparator</code>.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Stream<T> parallel()</code></td>
<td style="text-align: center;"><span class="small">N/A</span></td>
<td style="text-align: center;"><span class="small">Returns an equivalent stream that is parallel.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Stream<T> sequential()</code></td>
<td style="text-align: center;"><span class="small">N/A</span></td>
<td style="text-align: center;"><span class="small">Returns an equivalent stream that is sequential.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Stream<T> unordered()</code></td>
<td style="text-align: center;"><span class="small">N/A</span></td>
<td style="text-align: center;"><span class="small">Returns an equivalent stream that is unordered.</span></td>
</tr>
</table>
<p><br /></p>
<h2>Terminal operations</h2>
<p>You can also easily identify terminal operations, they always return something other than a stream.</p>
<p>After the terminal operation is performed, the stream pipeline is <i>consumed</i>, and can't be used anymore. For example:</p>
<p><code class="java hljs"><span class="hljs-keyword">int</span>[] digits = {<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span> , <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>};<br />
IntStream s = IntStream.of(digits);<br />
<span class="hljs-keyword">long</span> n = s.count();<br />
System.out.println(s.findFirst()); <span class="hljs-comment">// An exception is thrown</span></code></p>
<p>If you need to traverse the same stream again, you must return to the data source to get a new one. For example:</p>
<p><code class="java hljs"><span class="hljs-keyword">int</span>[] digits = {<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span> , <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>};<br />
<span class="hljs-keyword">long</span> n = IntStream.of(digits).count();<br />
System.out.println(IntStream.of(digits).findFirst()); <span class="hljs-comment">// OK</span></code></p>
<p>The following table summarizes the methods of the <code>Stream</code> interface that represent terminal operations.</p>
<table border="1" cellspacing="5" width="98%">
<tr>
<th>Method</th>
<th>Description</th>
</tr>
<tr>
<td style="text-align: center;"><code>boolean allMatch(Predicate<? super T> predicate)</code></td>
<td style="text-align: center;"><span class="small">Returns whether all elements of this stream match the provided predicate.<br /> If the stream is empty then <code>true</code> is returned and the predicate is not evaluated.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>boolean anyMatch(Predicate<? super T> predicate)</code></td>
<td style="text-align: center;"><span class="small">Returns whether any elements of this stream match the provided predicate.<br /> If the stream is empty then <code>false</code> is returned and the predicate is not evaluated.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>boolean noneMatch(Predicate<? super T> predicate)</code></td>
<td style="text-align: center;"><span class="small">Returns whether no elements of this stream match the provided predicate.<br /> If the stream is empty then <code>true</code> is returned and the predicate is not evaluated.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Optional<T> findAny()</code></td>
<td style="text-align: center;"><span class="small">Returns an <code>Optional</code> describing some element of the stream.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Optional<T> findFirst()</code></td>
<td style="text-align: center;"><span class="small">Returns an <code>Optional</code> describing the first element of this stream.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code><R,A> R collect(Collector<? super T,A,R> collector)</code></td>
<td style="text-align: center;"><span class="small">Performs a mutable reduction operation on the elements of this stream using a <code>Collector</code>.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>long count()</code></td>
<td style="text-align: center;"><span class="small">Returns the count of elements in this stream.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>void forEach(Consumer<? super T> action)</code></td>
<td style="text-align: center;"><span class="small">Performs an action for each element of this stream.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>void forEachOrdered(Consumer<? super T> action)</code></td>
<td style="text-align: center;"><span class="small">Performs an action for each element of this stream, in the encounter order of the stream if the stream has a defined encounter order.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Optional<T> max(Comparator<? super T> comparator)</code></td>
<td style="text-align: center;"><span class="small">Returns the maximum element of this stream according to the provided <code>Comparator</code>.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Optional<T> min(Comparator<? super T> comparator)</code></td>
<td style="text-align: center;"><span class="small">Returns the minimum element of this stream according to the provided <code>Comparator</code>.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>T reduce(T identity, BinaryOperator<T> accumulator)</code></td>
<td style="text-align: center;"><span class="small">Performs a reduction on the elements of this stream, using the provided identity value and an associative accumulation function, and returns the reduced value.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Object[] toArray()</code></td>
<td style="text-align: center;"><span class="small">Returns an array containing the elements of this stream.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code><A> A[] toArray(IntFunction<A[]> generator)</code></td>
<td style="text-align: center;"><span class="small">Returns an array containing the elements of this stream, using the provided generator function to allocate the returned array.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Iterator<T> iterator()</code></td>
<td style="text-align: center;"><span class="small">Returns an iterator for the elements of the stream.</span></td>
</tr>
<tr>
<td style="text-align: center;"><code>Spliterator<T> spliterator()</code></td>
<td style="text-align: center;"><span class="small">Returns a spliterator for the elements of the stream.</span></td>
</tr>
</table>
<p><br /></p>
<h2>Lazy operations</h2>
<p>Intermediate operations are deferred until a terminal operation is invoked. The reason is that intermediate operations can usually be merged or optimized by a terminal operation.</p>
<p>Let's take for example this stream pipeline:</p>
<p><code class="java hljs">Stream.of(<span class="hljs-string">"sun"</span>, <span class="hljs-string">"pool"</span>, <span class="hljs-string">"beach"</span>, <span class="hljs-string">"kid"</span>, <span class="hljs-string">"island"</span>, <span class="hljs-string">"sea"</span>, <span class="hljs-string">"sand"</span>)<br />
.map(str -> str.length())<br />
.filter(i -> i > <span class="hljs-number">3</span>)<br />
.limit(<span class="hljs-number">2</span>)<br />
.forEach(System.out::println);</code></p>
<p>Here's what it does:</p>
<ul>
<li>It generates a stream of strings,</li>
<li>Then convert the stream to a stream of <code>int</code>s (representing the length of each string)</li>
<li>Then it filters the lengths greater than three,</li>
<li>Then it grabs the first two elements of the stream and</li>
<li>Finally, prints those two elements.</li>
</ul>
<p>And you may think the map operation is applied to all seven elements, then the filter operation again to all seven, then it picks the first two, and finally it prints the values.</p>
<p>But this is not how it works. If we modify the lambda expressions of map and filter to print a message:</p>
<p><code class="java hljs">Stream.of(<span class="hljs-string">"sun"</span>, <span class="hljs-string">"pool"</span>, <span class="hljs-string">"beach"</span>, <span class="hljs-string">"kid"</span>, <span class="hljs-string">"island"</span>, <span class="hljs-string">"sea"</span>, <span class="hljs-string">"sand"</span>)<br />
.map(str -> {<br />
System.out.println(<span class="hljs-string">"Mapping: "</span> + str);<br />
<span class="hljs-keyword"><font color="#000000"> </font>return</span> str.length();<br />
})<br />
.filter(i -> {<br />
System.out.println(<span class="hljs-string">"Filtering: "</span> + i);<br />
<span class="hljs-keyword"> return</span> i > <span class="hljs-number">3</span>;<br />
})<br />
.limit(<span class="hljs-number">2</span>)<br />
.forEach(System.out::println);</code></p>
<p>The order of evaluation will be revealed:</p>
<p><code class="java hljs">Mapping: sun<br />
Filtering: <span class="hljs-number">3<br /></span>Mapping: pool<br />
Filtering: <span class="hljs-number">4<br /></span><span class="hljs-number">4<br /></span>Mapping: beach<br />
Filtering: <span class="hljs-number">5<br /></span><span class="hljs-number">5</span></code></p>
<p>From this example, we can see the stream didn't apply all the operations on the pipeline to all elements, only until if it finds the elements needed to return a result (due to the <code>limit(2)</code> operation). This is called <i>short-circuiting</i>.</p>
<p>Short-circuit operations cause intermediate operations to be processed until a result can be produced.</p>
<p>In such a way, because of lazy and short-circuit operations, streams don't execute all operations on all their elements. Instead, the elements of the stream go through a pipeline of operations until the point a result can be deduced or generated.</p>
<p>You can see short-circuiting as a subclassification. There's only one short-circuit intermediate operation, while the rest are terminal:</p>
<p><b>INTERMEDIATE</b></p>
<p><code class="java hljs"><span class="hljs-function">Stream<T> <span class="hljs-title">limit</span><span class="hljs-params">(<span class="hljs-keyword">long</span> maxSize)</span></span></code></p>
<p>(Because it doesn't need to process all the elements of the stream to create a stream of a given size)</p>
<p><b>TERMINAL</b></p>
<p><code class="java hljs"><span class="hljs-function"><span class="hljs-keyword">boolean</span> <span class="hljs-title">anyMatch</span><span class="hljs-params">(Predicate<? <span class="hljs-keyword">super</span> T> predicate)<br /></span><span class="hljs-keyword">boolean</span> <span class="hljs-title">allMatch</span><span class="hljs-params">(Predicate<? <span class="hljs-keyword">super</span> T> predicate)<br /></span><span class="hljs-keyword">boolean</span> <span class="hljs-title">noneMatch</span><span class="hljs-params">(Predicate<? <span class="hljs-keyword">super</span> T> predicate)<br /></span>Optional<T> <span class="hljs-title">findFirst</span><span class="hljs-params">()<br /></span>Optional<T> <span class="hljs-title">findAny</span><span class="hljs-params">()</span></span></code></p>
<p>(Because as soon as you find a matching element, there's no need to continuing processing the stream)</p>
<p>In the next chapters, we'll review the rest of the operations of the <code>Stream</code> interface.</p>
<h2>Key Points</h2>
<ul>
<li>Streams can be defined as wrappers for collections and arrays. They wrap an existing collection (or another data source) to support operations expressed with lambdas, so you specify what you want to do, not how to do it.</li>
<li>These are the characteristics of a stream:
<ul>
<li>Streams work perfectly with lambdas.</li>
<li>Streams don't store its elements.</li>
<li>Streams are immutable.</li>
<li>Streams are not reusable.</li>
<li>Streams don't support indexed access to their elements.</li>
<li>Streams are easily parallelizable.</li>
<li>Stream operations are lazy when possible.</li>
</ul>
</li>
<li>Stream operations can be chained to form a pipeline. To set up this pipeline you:
<ol>
<li>Create the stream.</li>
<li>Apply zero or more intermediate operations to transform the initial stream into new streams.</li>
<li>Apply a terminal operation to generate a result or a "side-effect".</li>
</ol>
</li>
<li>There are many ways to create a stream. The most popular are: <code class="java hljs"><span class="hljs-comment">// From an existing collection<br /></span>List<String> words = Arrays.asList(<span class="hljs-keyword">new</span> String[]{<span class="hljs-string">"hello"</span>, <span class="hljs-string">"hola"</span>, <span class="hljs-string">"hallo"</span>, <span class="hljs-string">"ciao"</span>});<br />
Stream<String> s1 = words.stream();<br />
<br />
<span class="hljs-comment">// From individual elements<br /></span>Stream<String> s2 = Stream.of(<span class="hljs-string">"hello"</span>, <span class="hljs-string">"hola"</span>, <span class="hljs-string">"hallo"</span>, <span class="hljs-string">"ciao"</span>);<br />
<span class="hljs-comment"><br />
// From an array<br /></span>String[] words = {<span class="hljs-string">"hello"</span>, <span class="hljs-string">"hola"</span>, <span class="hljs-string">"hallo"</span>, <span class="hljs-string">"ciao"</span>};<br />
Stream<String> s3 = Stream.of(words);</code></li>
<li>Don't use <code>Stream<T>.of()</code> when working with primitives. Instead use <code>Arrays.stream</code> or the primitive versions of <code>Stream</code>: <code class="java hljs"><span class="hljs-keyword">int</span>[] nums = {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>};<br />
IntStream s1 = Arrays.stream(nums);<br />
IntStream s2 = IntStream.of(nums);</code></li>
<li>Intermediate operations such as <code>map</code> or <code>filter</code> always return a new stream and are divided into <i>stateless</i> and <i>stateful</i> operations, and they are lazy, meaning that they are deferred until a terminal operation is invoked.</li>
<li>Terminal operations such as <code>count</code> or <code>forEach</code> always return something other than a stream.</li>
<li>Short-circuit operations cause intermediate operations to be processed until a result can be produced.</li>
<li>In such a way, because of lazy and short-circuit operations, streams don't execute all operations on all their elements, but until the point a result can be deduced or generated.</li>
</ul>
<h2>Self Test</h2>
<p>1. Given:</p>
<p><code class="java hljs"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Question_12_1</span></span> {<br />
<span class="hljs-function"><span class="hljs-keyword"><font color="#000000"> </font>public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span></span> {<br />
IntStream.range(<span class="hljs-number">1</span>, <span class="hljs-number">10</span>)<br />
.filter(i -> {<br />
System.out.print(<span class="hljs-string">"1"</span>);<br />
<span class="hljs-keyword"><font color="#000000"> </font>return</span> i % <span class="hljs-number">2</span> == <span class="hljs-number">0</span>;<br />
})<br />
.filter(i -> {<br />
System.out.print(<span class="hljs-string">"0"</span>);<br />
<span class="hljs-keyword"><font color="#000000"> </font>return</span> i > <span class="hljs-number">3</span>;<br />
})<br />
.limit(<span class="hljs-number">1</span>)<br />
.forEach(i -> {<br />
System.out.print(i);<br />
});<br />
}<br />
}</code></p>
<p>What is the result?<br /> A. <code>101010104</code><br /> B. <code>1111111110000000004</code><br /> C. <code>11041106</code><br /> D. <code>1101104</code><br /> E. An exception is thrown</p>
<p>2. Which of the following are intermediate operations?<br /> A. <code>limit</code><br /> B. <code>peek</code><br /> C. <code>anyMatch</code><br /> D. <code>skip</code></p>
<p>3. Which of the following are terminal operations?<br /> A. <code>sorted</code><br /> B. <code>flatMap</code><br /> C. <code>max</code><br /> D. <code>distinct</code></p>
<p>4. Which of the following are short-circuit operations?<br /> A. <code>reduce</code><br /> B. <code>parallel</code><br /> C. <code>findNone</code><br /> D. <code>findFirst</code></p>
<p>5. Given:</p>
<p><code class="java hljs"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Question_12_2</span></span> {<br />
<span class="hljs-function"><span class="hljs-keyword"><font color="#000000"> </font>public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span></span> {<br />
IntStream.range(<span class="hljs-number">1</span>, <span class="hljs-number">5</span>).count().limit(<span class="hljs-number">4</span>);<br />
}<br />
}</code></p>
<p>What is the result?<br /> A. <code>5</code><br /> B. <code>4</code><br /> C. <code>1</code><br /> D. Compilation error<br /> E. An exception is thrown</p>
<div class="answers">
<a href="ch12a.html" target="_blank">Open answers page</a>
</div>
<div class="book-info"></div>
<div class="linkbox">
<div class="previous">
<a href="ch11.html">11. Method References</a>
</div>
<div class="next">
<a href="ch13.html">13. Iterating and Filtering Collections</a>
</div>
<div style="clear:both;"></div>
</div>
</div>
</div>
</body>
</html>