This example will show various code snippets to demonstrate stream intermediate operations. Intermediate operations return another Stream which allows you to call multiple operations in a form of a query. Intermediate operations do not get executed until a terminal operation is invoked as there is a possibility they could be processed together when a terminal operation is executed.
filter
Stream.filter operation will return a new stream that contains elements that match its predicate. Below we will use a lambda expression to create a java.util.function.Predicate that will check if the integer is less than three. The terminal Stream.count operation will return the number of elements in the stream.
@Test
public void intermediate_filter() {
long elementsLessThanThree = Stream.of(1, 2, 3, 4)
.filter(p -> p.intValue() < 3).count();
assertEquals(2, elementsLessThanThree);
}
map
Stream.map will transform the elements elements in a stream using the provided java.util.function.Function. A function is a method that accepts an argument and produces a result. They are commonly used for transforming collections and can be seen in the transforming a list to a map example.
In the snippet below we will create a function using a lambda expression that will replace any null strings in the stream with [unknown].
@Test
public void intermediate_map() {
List<String> strings = Stream.of("one", null, "three").map(s -> {
if (s == null)
return "[unknown]";
else
return s;
}).collect(Collectors.toList());
assertThat(strings, contains("one", "[unknown]", "three"));
}
flatmap
Stream.flatmap will transform each element into zero or more elements by a way of another stream. To demonstrate, we pulled code snippet from how to count unique words in a file example. Using java 7 file api, we will read all lines from a file as a Stream. Then calling Stream.flatmap we will break the line into words elements. If we had a line made up of "the horse was walking down the street", this line would be broken into ["the", "horse", "was", "walking", "down", "the", "street"]. Calling the the Stream.distinct method will find all unique occurrences of words.
@Test
public void count_distinct_words_java8() throws IOException {
File file = new File(sourceFileURI);
long uniqueWords = java.nio.file.Files
.lines(Paths.get(file.toURI()), Charset.defaultCharset())
.flatMap(line -> Arrays.stream(line.split(" ."))).distinct()
.count();
assertEquals(80, uniqueWords);
}
peek
The Stream.peek is extremely useful during debugging. It allows you to peek into the stream before an action is encountered. In this snippet we will filter any strings with a size of great than four then call the peek at the stream before the map is called. The peek operation will print out the elements of 'Badgers', 'finals' and 'four'.
@Test
public void intermediate_peek() {
List<String> strings = Stream.of("Badgers", "finals", "four")
.filter(s -> s.length() >= 4).peek(s -> System.out.println(s))
.map(s -> s.toUpperCase()).collect(Collectors.toList());
assertThat(strings, contains("BADGERS", "FINALS", "FOUR"));
}
distinct
Stream.distinct will find unique elements in a stream according to their .equals behavior. A use case to use distinct is when you want to find the distinct number of words in a file.
@Test
public void intermediate_distinct() {
List<Integer> distinctIntegers = IntStream.of(5, 6, 6, 6, 3, 2, 2)
.distinct()
.boxed()
.collect(Collectors.toList());
assertEquals(4, distinctIntegers.size());
assertThat(distinctIntegers, contains(
5, 6, 3, 2));
}
sorted
The Stream.sorted method will return a stream sorted according to natural order. Below, we will create a stream of ints then calling the sort which will return the numbers in ascending order.
@Test
public void intermediate_sorted() {
List<Integer> sortedNumbers = Stream.of(5, 3, 1, 3, 6).sorted()
.collect(Collectors.toList());
assertThat(sortedNumbers, contains(1, 3, 3, 5, 6));
}
limit
Stream.limit is a useful technique to limit the number or truncate elements to be processed in the stream. Similar to limit elements in a list, we can perform the same behavior within a stream as shown below.
@Test
public void intermediate_limit() {
List<String> vals = Stream.of("limit", "by", "two").limit(2)
.collect(Collectors.toList());
assertThat(vals, contains("limit", "by"));
}