Streams API

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 41

Streams in Java provide a powerful and efficient way to process data by applying various sequential and

parallel aggregate operations. The Stream API in Java 8 introduced the concept of streams and stream
classes in Java, which offer specialized functionality for manipulating and transforming data. Developers
can utilize the Stream API in Java to write code that is more concise, expressive, and efficient.

The Stream API in Java provides a rich set of operations that can be applied to streams, such as filtering,
mapping, and reducing. The Stream API in Java provides a high-level abstraction for working with
streams and offers a wide range of operations to manipulate and process data.

Stream.of(1, 2, 3, 4, 5) // Stream source

.filter(x -> x % 2 == 0) // Intermediate operation

.collect(Collectors.toList()) // Terminal operation

Example of Streams in Java:

Here's an example that demonstrates the use of Streams in Java to filter and transform a collection of
names:
List<String> names = Arrays.asList("John", "Jane", "Adam", "Eve", "Mike");

List<String> filteredNames = names.stream()

.filter(name -> name.startsWith("J"))

.map(String::toUpperCase)

.collect(Collectors.toList());

System.out.println(filteredNames); // Output: [JOHN, JANE]

In this example, we create a stream from the names list, filter the names starting with "J", convert them
to uppercase using the map operation, and collect the results into a new list using the collect terminal
operation. The output is the filtered and transformed names: [JOHN, JANE].

Different Operations on Streams

Stream provides various operations that can be chained together to produce results. Stream operations
can be classified into two types.

Intermediate Operations

Terminal Operations

1. Intermediate Operations

Intermediate operations return a stream as the output, and intermediate operations are not executed
until a terminal operation is invoked on the stream. This is called lazy evaluation, and it is discussed in
detail in the later section (Lazy Evaluation).

filter()

The filter() method returns a stream with the stream's elements that match the given predicate.
Predicate is a functional interface in Java that accepts a single input and can return a boolean value.
Example

public class Main {

public static void main(String[] args) {

final List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

final List<Integer> ans = list.stream()

.filter(value -> value % 2 == 0)

.collect(Collectors.toList());

System.out.println(Arrays.toString(ans.toArray()));

Output

[2, 4]

Explanation This example filters the even values based on the predicate (value -> value % 2 == 0) passed
to it.

map()

The map() method returns a stream with the resultant elements after applying the given function on the
stream elements.
Example

public class Main {

public static void main(String[] args) {

final List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

final List<Integer> ans = list.stream()

.map(value -> value * 10)

.collect(Collectors.toList());

System.out.println(Arrays.toString(ans.toArray()));

Output

[10, 20, 30, 40, 50]

Explanation

In the example the map() method is called with the function value -> value * 10 on the stream. The
function is called for all values of the stream, and hence the result contains all stream values multiplied
by 10.

sorted()
The sorted() method returns a stream with the elements of the stream sorted according to natural order
or the provided Comparator.

Example

public class Main {

public static void main(String[] args) {

final List<Integer> list = new ArrayList<>(Arrays.asList(5, 1, 3, 4, 2));

System.out.println("Ascending Order");

list.stream().sorted()

.forEach(System.out::println);

System.out.println("\nDescending Order");

list.stream().sorted(Comparator.reverseOrder())

.forEach(System.out::println);

Output

Ascending Order

5
Descending Order

Explanation

The sorted() method without any parameters sorts the elements in ascending order.

The sorted() method with the comparator Comparator.reverseOrder() sorts the element in the
descending order.

distinct()

This distinct() method returns a stream consisting of distinct elements of the stream (i.e.) it removes
duplicate elements.

Example

public class Main {

public static void main(String[] args) {

final List<Integer> list = new ArrayList<>(Arrays.asList(1, 1, 2, 2, 3));

final List<Integer> ans = list.stream()

.distinct()
.collect(Collectors.toList());

System.out.println("Distinct List: " + Arrays.toString(ans.toArray()));

Output

Distinct List: [1, 2, 3]

Explanation

The distinct() method removes the duplicate values 1 and 2.

peek()

The peek() method returns a stream consisting of the elements of the stream after performing the
provided action on each element. This is useful when we want to print values after each intermediate
operation.

Example

public class Main {

public static void main(String[] args) {

final List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

final List<Integer> ans = list.stream()


.filter(value -> value % 2 == 0)

.peek(value -> System.out.println("Filtered " + value))

.map(value -> value * 10)

.collect(Collectors.toList());

System.out.println(Arrays.toString(ans.toArray()));

Output

Filtered 2

Filtered 4

[20, 40]

Explanation

We printed the filtered values using the peek() method after the intermediate filter() operation.

limit()

The limit() method returns a stream with the stream elements limited to the provided size.

Example
public class Main {

public static void main(String[] args) {

final List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

final List<Integer> ans = list.stream()

.limit(3)

.collect(Collectors.toList());

System.out.println("Limited List: " + Arrays.toString(ans.toArray()));

Output

Limited List: [1, 2, 3]

Explanation

We limited the size of the stream to 3 using the limit(3) method.

skip()

This skip() method returns a stream consisting of the stream after discarding the provided first n
elements.

Example
public class Main {

public static void main(String[] args) {

final List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

final List<Integer> ans = list.stream()

.skip(2)

.collect(Collectors.toList());

System.out.println("Skipped List: " + Arrays.toString(ans.toArray()));

Output

Skipped List: [3, 4, 5]

Explanation The first two elements are skipped using the skip(2) method.

2. Terminal Operations

Terminal operations produce the results of the stream after all the intermediate operations are applied,
and we can no longer use the stream once the terminal operation is performed. forEach()

The forEach() method iterates and performs the specified action for each stream element. For parallel
stream, it doesn't guarantee to maintain the order of the stream.

Example
public class Main {

public static void main(String[] args) {

final List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

list.stream().forEach(System.out::println);

Output

Explanation

The forEach() method iterates and prints all the stream values.

forEachOrdered()

The forEachOrdered() method iterates and performs the specified action for each stream element. This
is similar to the forEach() method, and the only difference is that it maintains the order when the stream
is parallel.
public class Main {

public static void main(String[] args) {

Stream.of("A","B","C")

.parallel()

.forEach(x -> System.out.println("forEach: " + x));

Stream.of("A","B","C")

.parallel()

.forEachOrdered(x -> System.out.println("forEachOrdered: " + x));

Output

forEach: B

forEach: C

forEach: A

forEachOrdered: A

forEachOrdered: B

forEachOrdered: C

Explanation
From the output, we can see that the forEach() method doesn't maintain the order of the stream,
whereas the forEachOrdered() method maintains the order of the stream. collect() The collect() method
performs a mutable reduction operation on the elements of the stream using a Collector.

Mutable Reduction

A mutable reduction is an operation in which the reduced value is a mutable result container, like an
ArrayList.

Collector

A Collector is a class in Java that implements various reduction operations such as accumulating
elements into collections, summarizing elements, etc.

Example

public class Main {

public static void main(String[] args) {

List<Integer> evenList = Stream.of(1, 2, 3, 4, 5)

.filter(x -> x % 2 == 0)

.collect(Collectors.toList());

System.out.println(evenList);

Output
[2, 4]

Explanation

The filter(x -> x % 2 == 0) method return a stream that contains even numbers. The stream is then
converted to a list via collect(Collectors.toList()).

count()

The count() method returns the total number of elements in the stream.

Example

public class Main {

public static void main(String[] args) {

final List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

final long count = list.stream().count();

System.out.println("Count: " + count);

Output
Count: 5

Explanation

The count() method returns the total number of elements in the stream, 5.

reduce()

The reduce() method performs a reduction on the elements of the stream and returns the value.

Example

public class Main {

public static void main(String[] args) {

final List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

final int ans = list.stream().reduce(0, (value, sum) -> sum += value);

System.out.println("Sum: " + ans);

Output

Sum: 15
Explanation

The reduce() method is called with two arguments, an initial value (0) and the accumulator method
(value, sum) -> sum += value).

Each stream element will be added to the previous result to produce the sum.

toArray()

The toArray() method returns an array that contains the elements of the stream.

Example

public class Main {

public static void main(String[] args) {

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);

System.out.println(Arrays.toString(stream.toArray()));

Output

[1, 2, 3, 4, 5]

Explanation

The toArray() method returns an array with the elements of the stream.
min() and max()

The min() and max() methods return an Optional that contains the minimum and maximum elements of
the stream, respectively, according to the provided comparator.

Example

public class Main {

public static void main(String[] args) {

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);

int minimum = stream.min((a, b) -> Integer.compare(a, b)).get();

System.out.println("Minimum: " + minimum);

stream = Stream.of(1, 2, 3, 4, 5);

int maximum = stream.max((a, b) -> Integer.compare(a, b)).get();

System.out.println("Maximum: " + maximum);

Output

Minimum: 1

Maximum: 5

Explanation
The min() and max() methods return optionals that contain the minimum and maximum elements of the
stream respectively. The comparator used to compare the elements is (a, b) -> Integer.compare(a, b).
This comparator returns 0 if a == b, a negative value if a < b and, a positive value if a > b.

findFirst()

The findFirst() method returns an Optional that contains the first element of the stream or an empty
Optional if the stream is empty.

Example

public class Main {

public static void main(String[] args) {

final List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

Optional<Integer> ans = list.stream().findFirst();

ans.ifPresent(value -> System.out.println("First Value: " + value));

Output

First Value: 1

Explanation The findFirst() method returns an Optional with the first element of the stream, which is 1.
findAny()

The findAny() method returns an Optional containing some element of the stream or an empty Optional
if the stream is empty.

Example

public class Main {

public static void main(String[] args) {

final List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

Optional<Integer> ans = list.stream().findAny();

ans.ifPresent(value -> System.out.println("Any Value: " + value));

Output

Any Value: 1

Explanation

The findAny() method can return any element in this stream. In this example, it returns 1. noneMatch()
When no stream elements match the specified predicate, the noneMatch() method returns true,
otherwise false. If the stream is empty, it returns true.
Example

public class Main {

public static void main(String[] args) {

final List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

boolean containsTwo = list.stream().noneMatch(value -> value == 2);

boolean containsZero = list.stream().noneMatch(value -> value == 0);

System.out.println("Is 2 present: " + containsTwo);

System.out.println("Is 0 present: " + containsZero);

Output

Is 2 present: false

Is 0 present: true

Explanation

The first noneMatch(value -> value == 2) returns false because there is a 2 in the stream.

The second noneMatch(value -> value == 0) returns true because there is no 0's in the stream.

allMatch()
When all the stream elements meet the specified predicate, the allMatch() method returns true,
otherwise false. If the stream is empty, it returns true.

Example

public class Main {

public static void main(String[] args) {

final List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

boolean isAllEven = list.stream().allMatch(value -> value == 2);

System.out.println("Is all even: " + isAllEven);

Output

Is all even: false

Explanation

The allMatch(value -> value == 2) returns false because there are other elements in the stream apart
from 2.

anyMatch()
When any stream element matches the specified predicate, the anyMatch() method returns true,
otherwise false. If the stream is empty, it returns false.

Example

public class Main {

public static void main(String[] args) {

final List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

boolean isTwoPresent = list.stream().anyMatch(value -> value == 2);

System.out.println("Is 2 present: " + isTwoPresent);

Output

Is 2 present: true

Explanation

The anyMatch(value -> value == 2) returns true because there is a 2 in the stream.

Different Ways to Create Streams in Java

Java streams can be created in many ways, including creating an empty stream, creating a stream from
an existing array, creating a stream from specified values, etc.
Stream.empty()

Stream.empty() creates an empty stream without any values. This avoids null pointer exceptions when
calling methods with stream parameters. We create empty streams when we want to add objects to the
stream in the program.

Syntax

Stream<T> stream = Stream.empty();

Example

public class Main {

public static void main(String[] args) {

Stream<Integer> stream = Stream.empty();

System.out.println("Size: " + stream.count());

Output

Size: 0

Explanation
The Stream.empty() method created an empty stream without any values in it. Hence calling count()
method on the stream returned 0.

Stream.builder()

Stream.builder() returns a builder (a design pattern that allows us to construct an object step-by-step)
that can be used to add objects to the stream. The objects are added to the builder using the add()
method. Calling build() method on the builder creates an instance of the Stream. This implementation of
Stream creation is based on the famous Builder Design Pattern.

Syntax

Stream.Builder<T> builder = Stream.builder();

Stream<T> stream = builder.build();

Example

public class Main {

public static void main(String[] args) {

Stream.Builder<String> builder = Stream.builder();

builder.add("Tony Stark")

.add("Steve Rogers")

.add("Thor Odinson");

Stream<String> stream = builder.build();


stream.forEach(System.out::println);

Output

Tony Stark

Steve Rogers

Thor Odinson

Explanation

The Stream.builder() method returned a Stream.Builder instance and it is used to add strings to the
builder instance. The Stream instance is created from the builder by calling the build() method.

Stream.of()

Stream.of() method creates a stream with the specified values. This method accepts both single and
multiple values. It does the work of declaring and initializing a stream.

Syntax

// Single value

Stream<T> stream = Stream.of(T value);

// Multiple values

Stream<T> stream = Stream.of(T... values);


Example

public class Main {

public static void main(String[] args) {

Stream<Integer> stream1 = Stream.of(1);

System.out.println("Size of Stream1: " + stream1.count());

Stream<Integer> stream2 = Stream.of(1, 2, 3);

System.out.println("Size of Stream2: " + stream2.count());

Output

Size of Stream1: 1

Size of Stream2: 3

Explanation

We created two streams stream1 and stream2 by passing single (1) and multiple values (1, 2, 3) to the
Stream.of() method.

Arrays.stream()

Arrays.stream() method creates a stream instance from an existing array. The resulting stream instance
will have all the elements of the array.
Syntax

Stream<T> stream = Arrays.stream(T[] array);

Example

public class Main {

public static void main(String[] args) {

Integer[] array = new Integer[] {1, 2, 3, 4, 5};

Stream<Integer> stream = Arrays.stream(array);

System.out.println("Size: " + stream.count());

Output

Size: 5

Explanation

The stream instance is created from the values of the array passed to the Arrays.stream() method. The
created stream instance will have all the values of the array.

Stream.concat()
Stream.concat methods combine two existing streams to produce a new stream. The resultant stream
will have all the elements of the first stream followed by all the elements of the second stream.

Syntax

Stream<T> stream = Stream.concat(Stream<T> stream1, Stream<T> stream2);

Example

public class Main {

public static void main(String[] args) {

Stream<Integer> stream1 = Stream.of(1, 2, 3);

Stream<Integer> stream2 = Stream.of(4, 5);

Stream<Integer> stream3 = Stream.concat(stream1, stream2);

System.out.println("Elements of concatenated stream");

stream3.forEach(System.out::println);

Output

Elements of concatenated stream

2
3

Explanation

In this example, stream3 is created by combining stream1 and stream2. stream3 contains all the
elements of stream1 followed by all the elements of stream2.

Stream.generate()

Stream.generate() returns an infinite sequential unordered stream where the values are generated by
the provided Supplier.

Let's understand the important terms.

Infinite The values in the stream are infinite (i.e.) unlimited.

Unordered Repeated execution of the stream might produce different results.

Supplier A functional interface in Java represents an operation that takes no argument and returns a
result.

Stream.generate() is useful to create infinite values like random integers, UUIDs (Universally Unique
Identifiers), constants, etc. Since the resultant stream is infinite, it can be limited using the limit()
method to make it run infinite time.

Syntax
Stream<T> stream = Stream.generate(Supplier<T> supplier);

Example

public class Main {

public static void main(String[] args) {

List<UUID> uuids = Stream.generate(UUID::randomUUID)

.limit(5)

.collect(Collectors.toList());

uuids.forEach(System.out::println);

Output

7dc6148c-4fa4-431d-b2a7-2f7ee5c64193

07e25f0d-d739-46ef-8117-e4947c79d09c

d8a840b4-b2cd-44fc-8242-910a742fe6bd

3652935b-c626-442d-8139-03929f3eae4a

4b5e8446-db37-4b4e-a539-7c5b16878537

Explanation
In this example, we created an infinite stream of UUIDs using the Stream.generate() method.

The Supplier is UUID::randomUUID that generates random UUIDs.

Since the stream is infinite, it is limited using the limit() method.

Stream.iterate()

Stream.iterate() returns a infinite sequential ordered stream stream where the values are generated by
the provided UnaryOperator. Lets understand the important terms.

Infinite The values in the stream are infinite (i.e. unlimited).

Ordered Repeated execution of the stream produces the same results.

UnaryOperator A functional interface in Java that takes one argument and returns a result that is of the
same type as its argument.

Stream.iterate() methods accept two arguments, an initial value called the seed value and a unary
operator. The first element of the resulting stream will be the seed value. The following elements are
created by applying the unary operator on the previous element.

Syntax

Stream<T> stream = Stream.iterate(T seed, UnaryOperator<T> unaryOperator);

Example

public class Main {

public static void main(String[] args) {

List<Integer> values = Stream.iterate(1, n -> n * 2)


.limit(5)

.collect(Collectors.toList());

values.forEach(System.out::println);

Output

16

Explanation

In this example, we created an infinite ordered stream using the Stream.iterate() method that generates
multiples of 2.

The first element of the stream is 1, which is the seed value passed. The following elements are created
by applying the unary operator n -> n * 2 on the previous element.

Since the stream is infinite, the results are limited using the limit() method.

Comparison Based Stream Operations

min and max

These terminal operations return the minimum and maximum element of a stream based on a specified
comparator. For example:
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 6);

Optional<Integer> min = numbers.stream().min(Integer::compare);

Optional<Integer> max = numbers.stream().max(Integer::compare);

System.out.println(min.orElse(0)); // Output: 1

System.out.println(max.orElse(0)); // Output: 8

distinct

The distinct operation filters out duplicate elements from a stream, based on their natural order or the
provided comparator. For example:

List<Integer> numbers = Arrays.asList(2, 5, 2, 8, 1, 5);

List<Integer> distinctNumbers = numbers.stream().distinct().collect(Collectors.toList());

System.out.println(distinctNumbers); // Output: [2, 5, 8, 1]

allMatch, anyMatch, and noneMatch

These terminal operations check if certain conditions are true for all, any, or none of the elements in a
stream. They return a boolean value indicating the result. For example:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

boolean allEven = numbers.stream().allMatch(num -> num % 2 == 0);

boolean anyEven = numbers.stream().anyMatch(num -> num % 2 == 0);

boolean noneNegative = numbers.stream().noneMatch(num -> num < 0);


System.out.println(allEven); // Output: false

System.out.println(anyEven); // Output: true

System.out.println(noneNegative); // Output: true

In the above example, allMatch checks if all numbers are even (false), anyMatch checks if any number is
even (true), and noneMatch checks if none of the numbers are negative (true).

Stream Short-circuit Operations

Stream short-circuit operations can be better understood with Java's logical && and || operators.

expression1 && expression2 doesn't evaluate expression2 if expression1 is false because false &&
anything is always false.

expression1 || expression2 doesn't evaluate expression2 if expression1 is true because true || anything
is always true.

Stream short-circuit operations are those that can terminate without processing all the elements in a
stream. Short-circuit operations can be classified into two types.

Intermediate short-circuit operations

Terminal short-circuit operations

Intermediate Short-Circuit Operations

Intermediate short-circuit operations produce a finite stream from an infinite stream. The intermediate
short-circuit operation in the Java stream is limit().

Example

public class Main {

public static void main(String[] args) {


Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);

stream.limit(3).forEach(System.out::println);

Output

Explanation

The method limit(3) reduced the stream size from 5 to 3.

Terminal Short-Circuit Operations

Terminal short-circuit operations are those that can produce the result before processing all the
elements of the stream. The terminal short-circuit operations in stream are findFirst(), findAny(),
allMatch(), anyMatch(), and noneMatch().

Example

public class Main {

public static void main(String[] args) {

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);


boolean ans = stream.peek(x -> System.out.println("Checking " + x))

.anyMatch(x -> x == 3);

System.out.println("Is 3 present: " + ans);

Ouput

Checking 1

Checking 2

Checking 3

Is 3 present: true

Explanation

The terminal operation anyMatch(x -> x == 3) halts once 3 is found and doesn't process the remaining
stream elements.

Parallel Stream

By default, all stream operations are sequential in Java unless explicitly specified as parallel. Parallel
streams are created in Java in two ways.

Calling the parallel() method on a sequential stream.

Calling parallelStream() method on a collection.


Parallel streams are useful when we have many independent tasks that can be processed
simultaneously to minimize the running time of the program.

parallel()

parallel() method is called on the existing sequential stream to make it parallel.

Example

public class Main {

public static void main(String[] args) {

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);

stream.parallel().forEach(System.out::println);

Output

Explanation
The stream instance is converted to parallel stream by calling stream.parallel(). Since the forEach()
method is called on a parallel stream, the output order will not be same as the input order because the
elements are processed parallel.

parallelStream()

parallelStream() is called on Java collections like List, Set, etc to make it a parallel stream in Java.

Example

public class Main {

public static void main(String[] args) {

List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

list.parallelStream().forEach(System.out::println);

Output

Explanation
The list object is converted to a parallel stream by calling the parallelStream() method.

Method Types and Pipelines

Intermediate operations transform or filter elements in a stream, returning a new stream. Examples:
filter, map, distinct, sorted, limit.

Terminal operations produce a result or side effect, marking the end of a stream. Examples: forEach,
collect, reduce, count, min, max, anyMatch, allMatch, noneMatch.

Short-circuiting operations can terminate stream processing early based on a condition. Examples:
findFirst, findAny, limit.

Pipelines chain intermediate and terminal operations, processing data in a fluent and expressive
manner. Each operation takes input from the previous and produces output for the next. Pipelines allow
concise and declarative coding. Result is obtained from the terminal operation.

Example of using method types and pipeline in streams:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

int sum = numbers.stream()

.filter(n -> n % 2 == 0)

.map(n -> n * 2)

.reduce(0, Integer::sum);

System.out.println(sum); // Output: 12
In this example, the stream pipeline starts with the stream() method on the numbers list. It then applies
the filter intermediate operation to keep only the even numbers, followed by the map operation to
double each number. Finally, the reduce terminal operation sums up all the elements in the stream. The
output is the sum of the doubled even numbers, which is 12. Use this Online Compiler to compile your
Java code.

Lazy Evaluation

Lazy evaluation (aka) call-by-need evaluation is an evaluation strategy that delays evaluating an
expression until its value is needed. All intermediate operations are performed on the stream only when
a terminal operation is invoked on it. Lazy evaluation is one of the critical characteristics of Java streams
that allows significant optimizations.

Example

Consider the below example where we created a stream that filters odd numbers.

public class Main {

public static void main(String[] args) {

Stream<Integer> stream = Stream.of(1, 2, 3)

.filter(x -> x % 2 == 1)

.peek(x -> System.out.println("Filtered " + x));

System.out.println("Result");

System.out.println(stream.collect(Collectors.toList()));

}
Output

Result

Filtered 1

Filtered 3

[1, 3]

Explanation

Each element of the above stream is passed to the filter() method where odd numbers are filtered and
then the peek() method where the filtered value is printed.

Finally, we print the text Result and the filtered values.

If we look at the statements, the ideal order of printing should be

Filtered 1

Filtered 2

Result

[1, 3]

But we got a different order because the intermediate operations filter() and peek() are not executed
until the terminal operation collect() is invoked on the stream.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy