Chapter 9 - Java for Beginners Course

Creating Streams

What is a Stream?

The concept of streams in Java was introduced in version 8 and provides us with a different way of operating on sequences of elements of a given type.

You can think of a stream as a pipe that contains a sequence of elements. These elements can be processed/transformed/filtered based on a set of operations that we provide.

For example, let’s assume we have a Stream<Integer> that:

  • Contains the sequence 1, 2, 4 and 5

  • Where we want to filter the elements and only allow even numbers

  • And then we want to collect our results in an ArrayList

This can be represented as follows:

Example of an Integer Stream of 4 elements with a filter and a terminal operation

The 3 concepts in the diagram, which we’ll cover in these sections, make up the stream pipeline that define how our data will be processed.

Creating a Stream<T>

Java provides us with different mechanisms to create a Stream<T> of elements. In this section we’ll cover 3 of the most common approaches to create a Stream.

Using the Stream.of methods

The Stream interface provides us with static utility methods to create a stream from a single element or an array of elements we have. For example, to create the Stream<Integer> in our example above we could do the following:

Stream<Integer> numbers = Stream.of(1, 2, 4, 5);

Or, alternatively, if we already have an array, we can pass it into the of method:

Integer[] array = { 1, 2, 4, 5 };
Stream<Integer> numbers = Stream.of(array)

Using the stream() method in Collection types

All implementations of the Collection interface in Java (for example, ArrayList and others covered in chapter 7), provide a stream() method that will create a Stream with the elements in the collection.

For example, if we had a List<Integer> with the elements in the example we could do the following:

List<Integer> input = Arrays.asList(1, 2, 4, 5);
Stream<Integer> numbers = input.stream();

Creating IntStream instances

The Stream<T> interface we are discussing is meant for objects of any type, however, it isn’t meant for primitive types. Java provides specialized stream interfaces that work with primitive types, like IntStream.

For example, if we want a stream of int values that has the sequence 1, 2, 3, 4, we can write:

IntStream intStream = IntStream.range(1, 5);
The IntStream.range method doesn’t include the last number (it is exclusive on the end). If you want to include both the start and the end, you can use IntStream.rangeClosed.

If you need a Stream<Integer> based on an IntStream you can use the boxed() method as follows:

IntStream intStream = IntStream.range(1, 5);
Stream<Integer> integers = intStream.boxed();

Notes about Streams

In this section we covered a couple of options to create a Stream in Java. Once you have a Stream ready, there are a couple of things that are important to note:

  • Stream pipelines can have zero or more intermediate operations. We’ll cover this in the next section.

  • Streams are sequences of elements, hence, the elements are processed in the order they arrive. However, streams can be created as parallel streams in which case the processing order isn’t guaranteed.

  • Streams are lazy. This means that no processing will occur until you provide a terminal operation.

  • In general, a Stream shouldn’t be reused. If you need to reuse a Stream it is a good practice to create a new Stream instance.

Code in GitHub

Get the code for this tutorial using the links below.

Project Repo
Download code for this step
Main class for this step
Dependencies

This is a list of recommended tutorials or courses that might be useful before starting this one.

Contents
Welcome to the Course!
Course Introduction
Chapter 1 - Building Blocks
Quick introduction to Java Variables Classes And Objects Class Example - Defining a class Object Examples - Creating instances Java Application Example - Running our first app Accessing class members - The dot operator Packages - Organizing the code
Chapter 2 - Primitives and Operators
Primitives Arithmetic Operators Assignment Operator Unary Operators Equality and Relational Operators Conditional Operators
Chapter 3 - Statements and Control Flow
Expressions Statements If-Then Statement If-Then-Else Statement More If Statements Switch Statement While and Do-While Statements For Statement Branching Statements Exception Handling
Chapter 4 - Code Example
Example Project - A Simple Vending Machine Adding money Delivering Items Giving Change
Chapter 5 - Classes and Interfaces
Introduction Access Level Modifiers Class Declaration - Class, Methods and Fields Class Declaration - Constructors Inheritance Basics Inheritance - Constructors Inheritance - Methods and Fields Polymorphism Abstract Classes and Methods Interfaces Static Class Members Class Composition Final Classes and Class Members Generic Classes
Chapter 6 - Base Object Behaviors
Introduction Type Comparison Type Casting Object Equality - The Contract Object Equality - Common Pitfalls Object String Representation Garbage Collection Object Comparison Primitive Wrappers and Autoboxing
Chapter 7 - Data Structures
Introduction Arrays - Declaration and Creation Arrays - Basic Operations Core Collection Interfaces List and ArrayList - Basic Operations ArrayList Internals Introduction to Hash Tables Map and HashMap - Basic Operations Set and HashSet - Basic Operations
Chapter 8 - Anonymous classes and lambdas
Introduction Filtering a List Anonymous Classes Lambdas Built-in Functional Interfaces
Chapter 9 - Streams
Introduction Creating Streams Intermediate Operations Terminal Operations