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

How to answer conflict-resolution interview questions

QUESTION 1: How do you deal with conflict? People aren’t going to get along with each other all the time. It’s just a fact. Employers want to know that you can respond to conflict diplomatically, says job-search and interview coach Thea Kelley. If you’re a my-way-or-the-highway type of personality, you’re not going to get very far in the interview. Start off by emphasizing communication and respectfulness as a means to conflict resolution. For example, “I always take the person aside and discuss the issue privately. I listen actively to make sure I understand the other person’s point of view, and I work with the person to develop a solution together.” Stress that even if you both don’t completely agree on the end result, you tried to at least meet each other halfway. Pro tip: “Don’t non verbally communicate resentment when telling a story,” Kelley advises. “Aggressive body language and tone of voice can show that you harbor bad feelings.” QUESTION 2: Tell me about a time when you had

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

Java Logger

In Java, logging is an important feature that helps developers to trace out the errors. Java is the programming language that comes with the logging approach. It provides a Logging API that was introduced in Java 1.4 version. It provides the ability to capture the log file. In this section, we are going to deep dive into the Java Logger API. Also, we will cover logging level, components, Logging handlers or appenders, logging formatters or layouts, Java Logger class, What is logging in Java? In Java, Logging is an API that provides the ability to trace out the errors of the applications. When an application generates the logging call, the Logger records the event in the LogRecord. After that, it sends to the corresponding handlers or appenders. Before sending it to the console or file, the appenders format that log record by using the formatter or layouts. Need for Logging It provides the complete tracing information of the application. It records the critical failure if any occur in