Skip to main content

The Java 8 Stream API

1 Overview

In this comprehensive tutorial, we'll go through the practical uses of Java 8 Streams from creation to parallel execution.To understand this material, readers need to have a basic knowledge of Java 8 (lambda expressions, Optional, method references) and of the Stream API.

2 Stream Creation

There are many ways to create a stream instance of different sources. Once created, the instance will not modify its source, therefore allowing the creation of multiple instances from a single source.

Empty Stream

We should use the empty() method in case of the creation of an empty stream:
Stream<String> streamEmpty = Stream.empty();

We often use the empty() method upon creation to avoid returning null for streams with no element:

public Stream<String> streamOf(List<String> list) {
return list == null || list.isEmpty() ? Stream.empty() : list.stream();
}

2.2. Stream of Collection

We can also create a stream of any type of Collection (Collection, List, Set):

Collection<String> collection = Arrays.asList("a", "b", "c");
Stream<String> streamOfCollection = collection.stream();

2.3. Stream of Array

An array can also be the source of a stream:

Stream<String> streamOfArray = Stream.of("a", "b", "c");

We can also create a stream out of an existing array or of part of an array:

String[] arr = new String[]{"a", "b", "c"};
Stream<String> streamOfArrayFull = Arrays.stream(arr);
Stream<String> streamOfArrayPart = Arrays.stream(arr, 1, 3);

2.4. Stream.builder()

When builder is used, the desired type should be additionally specified in the right part of the statement, otherwise the build() method will create an instance of the Stream<Object>:

Stream<String> streamBuilder =
Stream.<String>builder().add("a").add("b").add("c").build();

2.5. Stream.generate()

The generate() method accepts a Supplier<T> for element generation. As the resulting stream is infinite, the developer should specify the desired size, or the generate() method will work until it reaches the memory limit:

Stream<String> streamGenerated =
Stream.generate(() -> "element").limit(10);

The code above creates a sequence of ten strings with the value “element.”

2.6. Stream.iterate()

Another way of creating an infinite stream is by using the iterate() method:

Stream<Integer> streamIterated = Stream.iterate(40, n -> n + 2).limit(20);

The first element of the resulting stream is the first parameter of the iterate() method. When creating every following element, the specified function is applied to the previous element. In the example above the second element will be 42.

2.7. Stream of Primitives

Java 8 offers the possibility to create streams out of three primitive types: int, long and double. As Stream<T> is a generic interface, and there is no way to use primitives as a type parameter with generics, three new special interfaces were created: IntStream, LongStream, DoubleStream.

Using the new interfaces alleviates unnecessary auto-boxing, which allows for increased productivity:

IntStream intStream = IntStream.range(1, 3);
LongStream longStream = LongStream.rangeClosed(1, 3);

The range(int startInclusive, int endExclusive) method creates an ordered stream from the first parameter to the second parameter. It increments the value of subsequent elements with the step equal to 1. The result doesn't include the last parameter, it is just an upper bound of the sequence.

The rangeClosed(int startInclusive, int endInclusive) method does the same thing with only one difference, the second element is included. We can use these two methods to generate any of the three types of streams of primitives.

Since Java 8, the Random class provides a wide range of methods for generating streams of primitives. For example, the following code creates a DoubleStream, which has three elements:

Random random = new Random();
DoubleStream doubleStream = random.doubles(3);

2.8. Stream of String

We can also use String as a source for creating a stream with the help of the chars() method of the String class. Since there is no interface for CharStream in JDK, we use the IntStream to represent a stream of chars instead.

IntStream streamOfChars = "abc".chars();

The following example breaks a String into sub-strings according to specified RegEx:

Stream<String> streamOfString =
Pattern.compile(", ").splitAsStream("a, b, c");

2.9. Stream of File

Furthermore, Java NIO class Files allows us to generate a Stream<String> of a text file through the lines() method. Every line of the text becomes an element of the stream:

Path path = Paths.get("C:\\file.txt");
Stream<String> streamOfStrings = Files.lines(path);
Stream<String> streamWithCharset =
Files.lines(path, Charset.forName("UTF-8"));

The Charset can be specified as an argument of the lines() method.

Comments

Popular posts from this blog

Spring Security with JWT for REST API

Spring is considered a trusted framework in the Java ecosystem and is widely used. It’s no longer valid to refer to Spring as a framework, as it’s more of an umbrella term that covers various frameworks. One of these frameworks is Spring Security , which is a powerful and customizable authentication and authorization framework. It is considered the de facto standard for securing Spring-based applications. Despite its popularity, I must admit that when it comes to single-page applications , it’s not simple and straightforward to configure. I suspect the reason is that it started more as an MVC application -oriented framework, where webpage rendering happens on the server-side and communication is session-based. If the back end is based on Java and Spring, it makes sense to use Spring Security for authentication/authorization and configure it for stateless communication. While there are a lot of articles explaining how this is done, for me, it was still frustrating to set it up for the f

Why do I need to override the equals and hashCode methods in Java?

  Imagine you have this MyClass first = new MyClass( "a" , "first" ); MyClass second = new MyClass( "a" , "second" ); Override only  equals If only  equals  is overriden, then when you call  myMap.put(first,someValue)  first will hash to some bucket and when you call  myMap.put(second,someOtherValue)  it will hash to some other bucket (as they have a different  hashCode ). So, although they are equal, as they don't hash to the same bucket, the map can't realize it and both of them stay in the map. Although it is not necessary to override  equals()  if we override  hashCode() , let's see what would happen in this particular case where we know that two objects of  MyClass  are equal if their  importantField  is equal but we do not override  equals() . Override only  hashCode If you only override  hashCode  then when you call  myMap.put(first,someValue)  it takes first, calculates its  hashCode  and stores it in a given bucket. Then wh

Momo suicide game

Microsoft clamps down on sick 'Momo suicide game' in 'Minecraft' Microsoft is clamping down on the sick “Momo suicide challenge,” which recently infiltrated the wildly popular online game “Minecraft.”The tech giant owns “Minecraft” developer Mojang. The vile “Momo suicide game” has been garnering attention after spreading on WhatsApp, prompting police warnings. "Momo" is a viral challenge that asks people to add a contact via WhatsApp - they are then   urged   to commit self-harm or suicide. The "game" has fueled comparisons to the sinister " Blue Whale challenge " that led to reports of suicides in Russia and the U.S, as well as the online fictional character of "Slender Man." In 2014 two 12-year-old girls in Wisconsin  attempted to kill   a classmate in an attempt to please the horror character. The Buenos Aires Times recently  reported  that police in Argentina are investigating whether “Momo” is linked to the suicide of a 12-y