Java 8 Streams Tutorial With Code Examples
In this blog post, we are going to discuss Java 8 Streams features and provide lots of different code examples.
Java Streams bring functional programming to java and they’re supported starting in java 8 so if you have an older version of java, then you have to upgrade to java 8 to use Java Streams.
Why Use Java Streams?
Some of the advantages of streams:
- Streams will make you a more efficient java programmer (you’ll see that with very few lines of code you can actually achieve quite a lot using streams).
- They make heavy use of lambda expressions which are sort of disposable functions.
- ParallelStreams enables multi-threaded operations for large datasets very easily.
Streams Pipeline
In most cases, a streams pipeline consists of a
- source (where your data flows out of)
- followed by zero or more intermediate operations
- and one terminal operation
The source is going to stream a stream of elements.
That stream of elements can be filtered, sorted, or it can be mapped or different other series of operations applied to each element.
At the end, it can be either be collected or reduced or some other terminal operation but only one terminal operations is performed.
Stream Source
Stream source can come from collections, lists, sets, arrays of int, longs, double, strings, etc.
Stream Operations
Stream operations are either intermediate or terminal:
- Intermediate operations such as filter, map, or sort return a stream so that we can chain multiple intermediate operations.
- Terminal operations receive a stream and they can either return void or they can return a non stream result such as a reduction, e.g. reduce items to a list.
Intermediate Operations
- Zero or more intermediate operations are allowed.
- Order matters; for large datasets: filter first then sort or map.
- For very large datasets us ParallelStream to enable multiple threads.
Some of the intermediate operations include:
- anyMatch()
- distinct()
- filter()
- findFirst()
- flatmap()
- map()
- skip()
- sorted()
Terminal Operations
Only get one terminal operation is allowed.
- forEach applies the same function to each element for example print each element.
- collect saves all of the elements into a collection or a list or an array.
- all other options reduce the stream to a single summary element.
Some examples of reduce functions are:
- count()
- max()
- min()
- reduce()
Java Streams Code Examples
Now let’s see the above concepts in code examples.
Integer Stream
The first example is just an integer stream. We’re going to create an integer stream using the IntStream
class and its range function which gives us a range of integers.
The forEach
is our terminal operation. For each item, we’re just going
to print it out.
import java.io.IOException;
import java.util.stream.IntStream;
public class JavaStreams {
public static void main(String[] args) throws IOException {
IntStream
.range(1, 10)
.forEach(System.out::print);
System.out.println();
}
}
Output:
123456789
Integer Stream with Skip
The second example uses an integer stream but we added a skip()
here, so in this case, we’re going to skip the first 5 elements of our stream.
This will only be printing elements 6 through 9. We’re also using a simple lambda expression to print the item
import java.io.IOException;
import java.util.stream.IntStream;
public class JavaStreams {
public static void main(String[] args) throws IOException {
IntStream
.range(1, 10)
.skip(5)
.forEach(x -> System.out.println(x));
System.out.println();
}
}
Output:
6
7
8
9
Integer Stream with Sum
The third example, we again use the IntStream
to create our stream of objects however, we put that inside of a println()
statement as the parameter for the print line.
What we’re going to print is just the sum from range 1 to 5 in other words, 1 2 3 & 4 it’s going to print out only the sum of those numbers:
import java.io.IOException;
import java.util.stream.IntStream;
public class JavaStreams {
public static void main(String[] args) throws IOException {
System.out.println(
IntStream
.range(1, 5)
.sum());
System.out.println();
}
}
Output:
10
Stream.of
The next example uses the Stream.of
function, which is really handy because
you can stream integers, floating point values or strings or even objects.
In this example, we’re just going to do a straight alphabetical sort then we’re
going to find the first item using the findFirst()
function. Then, we just print out the first item in the list.
import java.io.IOException;
import java.util.stream.Stream;
public class JavaStreams {
public static void main(String[] args) throws IOException {
Stream.of("Ava", "Aneri", "Alberto")
.sorted()
.findFirst()
.ifPresent(System.out::println);
}
}
Output
Alberto
Stream from Array, sort, filter and print
In our next example, we’re going to stream from an array. Then we’re going to sort, filter and then print.
Here, we’re going to filter out items only that start with s
.
We use a lambda expression that takes in X
which is each name and then it checks which ones start with letter s
and it’ll pass those on.
Then we’re going to sort them and then for each item that passes that sort we’re going to print it.
import java.io.IOException;
import java.util.Arrays;
public class JavaStreams {
public static void main(String[] args) throws IOException {
String[] names = {"Al", "Ankit", "Kushal", "Brent", "Sarika", "amanda", "Hans", "Shivika", "Sarah"};
Arrays.stream(names)
.filter(x -> x.startsWith("S"))
.sorted()
.forEach(System.out::println);
}
}
Output:
Sarah
Sarika
Shivika
Average of Integer Array
Now let’s take a look at how we can take the average of squares of an int array.
Here, we use the Arrays.stream()
function to stream the integers and then we’re going to use map()
to map each item each integer to its square.
import java.util.Arrays;
public class JavaStreams {
public static void main(String[] args) {
Arrays.stream(new int[] {2, 4, 6, 8, 10})
.map(x -> x * x)
.average()
.ifPresent(System.out::println);
}
}
Output:
44.0
Note it prints out double instead of an integer.
Stream from List, filter and print
In this example, we are going to stream from a list, filter those items and then print.
Note that within the map()
function, we are going to convert all names to lowercase.
import java.util.Arrays;
import java.util.List;
public class JavaStreams {
public static void main(String[] args) {
List<String> people = Arrays.asList("Al", "Ankit", "Brent", "Sarika", "amanda", "Hans", "Shivika", "Sarah");
people
.stream()
.map(String::toLowerCase)
.filter(x -> x.startsWith("a"))
.forEach(System.out::println);
}
}
Output:
al
ankit
amanda
We can see we have three names that start with a
and they’re all in lowercase.
Stream rows from text file, sort, filter, and print
In our next example, we’re going to stream rows from a text file. We’re going to sort, filter and print.
Let’s assume we have a file called bands.txt
with contents shown below:
Rolling Stones
Lady Gaga
Jackson Browne
Maroon 5
Arijit Singh
Elton John
John Mayer
CCR
Eagles
Pink
Aerosmith
Adele
Taylor Swift
We’re going to use Files.lines()
to create our stream which is going to give us a stream of a string for each line of the file.
Once we have our stream, we’re going to sort them and we’re going to filter out items that are greater than 13 characters and then print the items that are left.
Lastly, we have to close the file so we do bands.close
.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;
public class JavaStreams {
public static void main(String[] args) throws IOException {
Stream<String> bands = Files.lines(Paths.get("bands.txt"));
bands
.sorted()
.filter(x -> x.length() > 13)
.forEach(System.out::println);
bands.close();
}
}
Output:
Jackson Browne
Rolling Stones
We get two bands that have more than 13 characters.
Stream rows from text file and save to List
For this example, we will use the same text file as above.
We want to filter out items that contain the letters jit
, using x.contains()
which is just a string function.
Using the .collect()
we add all the ones with letters jit
to a list.
Once we have out list, we can then use the forEach
operator to print the items.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
public class JavaStreams {
public static void main(String[] args) throws IOException {
List<String> bands2 = Files.lines(Paths.get("bands.txt"))
.filter(x -> x.contains("jit"))
.collect(Collectors.toList());
bands2.forEach(x -> System.out.println(x));
}
}
Output:
Arijit Singh
Stream rows from CSV file and count
In this example, we stream rows from a CSV file and we’re going to count the good rows.
Suppose we have a file called data.txt
with the following contents:
A,12,3.7
B,17,2.8
C,14,1.9
D,23,2.7
E
F,18,3.4
Here, row E has no data, so we want to exclude that one from our stream.
In the following code, we’re going to read in each row then we need to split at the commas into an array so each row will become an array of items.
Then we apply a filter to filter out rows that don’t have three items.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;
public class JavaStreams {
public static void main(String[] args) throws IOException {
Stream<String> rows1 = Files.lines(Paths.get("data.txt"));
int rowCount = (int)rows1
.map(x -> x.split(","))
.filter(x -> x.length == 3)
.count();
System.out.println(rowCount + " rows.");
rows1.close();
}
}
Output:
5 rows
Reduction - sum
This example shows you how to use reduction. We’re going to reduce to a sum. Here, we have
a double stream using the Stream.of()
function. We’ve defined three doubles in three different arguments and we’re going to use the reduce function.
import java.util.stream.Stream;
public class JavaStreams {
public static void main(String[] args) {
double total = Stream.of(7.3, 1.5, 4.8)
.reduce(0.0, (Double a, Double b) -> a + b);
System.out.println("Total = " + total);
}
}
Output:
13.600000000000001