Stream is a new Java object, was introduced from Java 8. It helps us can manipulate on collections and arrays easier and more efficient. So what is it? In this article, I will introduce with you all about the Stream in Java.
First, consider the following example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.huongdanjava.example; import java.util.Arrays; import java.util.List; public class Example { public static void main(String[] args) { List<String> names = Arrays.asList("Khanh", "Thanh", "Dung"); names.stream() .filter(s -> s.startsWith("K")) .forEach(System.out::println); } } |
In this example, we have a List of the String object. From this List object, we convert it into the object of the Stream, then use this Stream object to filter the String starting with the “K” character, and finally print the String object beginning with “K” to the console.
Result:
Obviously, as you can see, using Stream with Lambda Expression makes our code easier to understand and read.
In the code above, we take the Stream object from the Collection object, would you feel like Stream is a Collection? It’s not, Stream is not a Collection.
Simply, Stream is a collection and array wrapper. It wraps an existing collection and other data sources to support manipulation on that collections or data sources using Lambda Expression. So, you just need specify what you want to do, and how to do it, Stream will worry about that.
Characteristics of Stream include:
- Stream perfect support for Lambda Expression.
- Stream does not contain collection or array elements.
- Stream is an immutable object.
- The stream is not reusable, meaning that once it is used, we can not call it again for using.
- We cannot use the index to access elements in the Stream.
- Stream supports parallel manipulation of elements in a collection or array.
- Stream supports lazy manipulation, as needed, new operations are performed.
To do this, most operations with Stream return a new Stream, which creates a chain containing a series of operations to perform the operation in the most optimal way. This chain is also called a pipeline.
There are three main steps to create a pipeline for Stream:
Create a new Stream.
The Stream interface in the java.util.stream package is the interface that represents a Stream. This interface only works with the data type is object.
With primitives, you can use Stream objects for those types of primitives, such as IntStream, LongStream, or DoubleStream.
We have many ways to create a new Stream:
Create a new Stream from a collection
Eg:
1 2 |
List<String> names = Arrays.asList("Khanh", "Thanh", "Dung"); Stream<String> stream = names.stream(); |
Create new Stream from certain values using the Stream interface.
Eg:
1 |
Stream<String> stream = Stream.of("Khanh", "Thanh", "Dung"); |
Create Stream from an array.
Eg:
1 2 |
String[] names = { "Khanh", "Thanh", "Dung" }; Stream<String> stream = Stream.of(names); |
Use 0 or more intermediate operations to convert an original Stream into a new one.
Stream has many intermediate operations to manipulate Stream, as shown at the beginning of the article we used:
1 2 |
Stream<String> stream = Stream.of("Khanh", "Thanh", "Dung"); stream.filter(s -> s.startsWith("K")).distinct(); |
Most intermediate operations return a new Stream object.
The important thing that you all need to know is even though we define many intermediate operations but they do not perform these operations immediately. Only when the terminal operation is called, these intermediates will be performed.
Use of terminal operation to retrieve results or a side-effect from defined intermediate operations.
You can easily to determine what is an intermediate operation, what is a terminal operation because the terminal operation will return a void or non-stream object.
After the terminal operation is called, Stream will no longer be available. If you want to use it again, you must create a new Stream from the collection or array you want.