Java 8 – How to create Stream

In this article, we will discuss various ways to create Stream in Java 1.8 version

1. Stream API method :

There are few useful methods available in Stream API which allows to create Stream from different input sources as listed below,

  1. of(T… values) :- Returns a sequential ordered stream whose elements are the specified values
  2. of(T t) :- Returns a sequential Stream containing a single element
  3. empty() :- Returns an empty sequential Stream
  4. generate(Supplier<T> s) :- Returns an infinite sequential unordered stream where each element is generated by the provided Supplier
  5. iterate(T seed, UnaryOperator<T> f) :- Returns an infinite sequential ordered Stream produced by iterative application of a function f to an initial element seed, producing a Stream

Note for example :-

  • All Stream API methods listed above are static
  • So, we can invoke directly as Stream.<staticMethodName>
  • we will use another Stream method forEach() to iterate through each elements of Stream and at the same printing to console for output

1.1 of(T… values) :

  • This method converts specified values into sequential ordered stream
  • Method signature :- static Stream of(T… values)
package net.bench.resources.stream.creation.example;

import java.util.stream.Stream;

public class StreamOfMethod {

	public static void main(String[] args) {

		// 1. square values
		System.out.println("1. Stream of Integer values in varargs - Square values : \n");

		Stream<Integer> stream1 = Stream.of(1, 4, 9, 16, 25, 36, 49, 64, 81, 100);
		stream1.forEach(i -> System.out.println(i));


		// 2. Integer array - fibonacci series
		Integer[] intArray = {1, 2, 3, 5, 8, 13, 21, 34, 55, 89};

		// 2.A create stream from Arrays
		System.out.println("\n2. Stream of Integer Array - Fibonacci series : \n");

		Stream<Integer> stream2 = Stream.of(intArray);
		stream2.forEach(i -> System.out.println(i));

		// 3. String Array
		String[] strArray = {
				"Vijay",
				"Ajith",
				"Kamal",
				"Rajni",
				"Suriya",
				"Vikram",
				"Dhanush"
		};

		// 3.A create stream from Arrays
		System.out.println("\n3. Stream of String Array - Names : \n");

		Stream<String> stream3 = Stream.of(strArray);
		stream3.forEach(str -> System.out.println(str));
	}
}

Output:

1. Stream of Integer values in varargs - Square values : 

1
4
9
16
25
36
49
64
81
100

2. Stream of Integer Array - Fibonacci series : 

1
2
3
5
8
13
21
34
55
89

3. Stream of String Array - Names : 

Vijay
Ajith
Kamal
Rajni
Suriya
Vikram
Dhanush

1.2 of(T t) :

  • This method converts specified single element into sequential stream
  • Method signature :- static Stream of(T t)
package net.bench.resources.stream.creation.example;

import java.util.stream.Stream;

public class StreamOfExample {

	public static void main(String[] args) {

		// 1. Integer value
		System.out.println("1. Converting single Integer element into Stream : ");

		Stream<Integer> stream1 = Stream.of(100);
		stream1.forEach(i -> System.out.println(i));

		// 2. String value
		System.out.println("\n2. Converting single String element into Stream : ");

		Stream<String> stream2 = Stream.of("BenchResources.Net");
		stream2.forEach(str -> System.out.println(str));
	}
}

Output:

1. Converting single Integer element into Stream : 
100

2. Converting single String element into Stream : 
BenchResources.Net

1.3 empty() :

  • This method returns an empty sequential Stream
  • When we try to print on console using Stream’s forEach() method, it won’t print anything to console because of empty Stream
  • Method signature :- static Stream empty()
package net.bench.resources.stream.creation.example;

import java.util.stream.Stream;

public class StreamEmptyMethod {

	public static void main(String[] args) {

		// empty Stream of String
		Stream<String> stream = Stream.empty();  	

		// displaying empty Stream of String
		stream.forEach(System.out::println); 
	}
}

Output:

Nothing to display

1.4 generate(Supplier<T> s) :

  • This method returns an infinite sequential unordered Stream
  • Each element is generated by the provided Supplier
  • Method signature :- static Stream generate(Supplier s)
package net.bench.resources.stream.creation.example;

import java.util.Random;
import java.util.stream.Stream;

public class StreamGenerateMethod {

	public static void main(String[] args) {

		System.out.println("1. Generating first 5 Random Integer numbers : \n");

		// 1. generating first 10 Random Integer number

		Stream.generate(new Random()::nextInt) // 1. Supplier to generate Random Integer
		.limit(5) // 2. intermediate operation to limit to 5 Integer numbers only
		.forEach(System.out::println); // 3. terminal operation to print to console


		System.out.println("\n2. Generating first 10 Random Integer"
				+ " within boundary of 1000 : \n");

		// 2. generating first 10 random Integer number within boundary of 1000

		Stream.generate(() -> (new Random()).nextInt(1000)) // 1. Supplier to generate Random
		.limit(10) // 2. intermediate operation to limit to 10 Integer numbers only
		.forEach(i -> System.out.println(i)); // 3. terminal operation to print to console


		System.out.println("\n3. Generating first 7 Random Double numbers : \n");

		// 3. generating first 7 Random double number

		Stream.generate(() -> (new Random()).nextDouble()) // 1. Supplier to generate Random
		.limit(7) // 2. intermediate operation to limit to 7 double numbers only
		.forEach(dbl -> System.out.println(dbl)); // 3. terminal operation to print to console
	}
}

Output:

1. Generating first 5 Random Integer numbers : 

1488825536
1390299139
356595619
941436694
-73125112

2. Generating first 10 Random Integer within boundary of 1000 : 

404
906
13
29
896
241
277
5
682
672

3. Generating first 7 Random Double numbers : 

0.050964282000754535
0.7763745295382452
0.9618087047680688
0.4930172107957018
0.47256213342121267
0.031847973917700334
0.5298139644068673

1.5 iterate(T seed, UnaryOperator<T> f) :

  • This method returns an infinite sequential ordered Stream
  • Each element is generated by the provided Function rather UnaryOperator<T> whose 1 input argument and return-type is same starting from provided seed
  • Method signature :- static Stream iterate(T seed, UnaryOperator f)
package net.bench.resources.stream.creation.example;

import java.util.stream.Stream;

public class StreamIterateMethod {

	public static void main(String[] args) {

		System.out.println("1. Iterating first 10 Integer numbers starting from 0 : \n");

		// 1. Stream of first 10 integer numbers

		Stream.iterate(0, i -> i+1) // 1. Function to iterate Integer numbers
		.limit(10) // 2. intermediate operation to limit to 10 numbers
		.forEach(System.out::println); // 3. terminal operation to print to console


		System.out.println("\n2. Iterating first 5 EVEN Integer numbers starting from 0 : \n");

		// 2. Stream of EVEN integer numbers

		Stream.iterate(0, i -> i+2) // 1. Function to iterate EVEN numbers
		.limit(5) // 2. intermediate operation to limit to 5 numbers
		.forEach(System.out::println); // 3. terminal operation to print to console


		System.out.println("\n3. Iterating first 7 ODD Integer numbers starting from 1 : \n");

		// 3. Stream of ODD integer numbers

		Stream.iterate(1, i -> i+2) // 1. Function to iterate ODD numbers
		.limit(7) // 2. intermediate operation to limit to 7 numbers
		.forEach(System.out::println); // 3. terminal operation to print to console
	}
}

Output:

1. Iterating first 10 Integer numbers starting from 0 : 

0
1
2
3
4
5
6
7
8
9

2. Iterating first 5 EVEN Integer numbers starting from 0 : 

0
2
4
6
8

3. Iterating first 7 ODD Integer numbers starting from 1 : 

1
3
5
7
9
11
13

2. Collection API method :

There are 2 useful methods available in Collection API which allows to create Stream as listed below,

  1. stream() :- Returns a sequential Stream with invoking collection as its source
  2. parallelStream() :- Returns a possibly parallel Stream with invoking collection as its source

2.1 stream() :

  • This method returns sequential Stream for the invoking Collection like List or Set
  • Then we can apply chain of multiple intermediate operation, if required
  • Finally apply terminal operation to get result be it collecting to another List/Set or printing to console or counting, etc.
  • Method signature :- default Stream stream()
package net.bench.resources.stream.creation.example;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class CollectionToStreamConversion {

	public static void main(String[] args) {

		System.out.println("1. List<Integer> to Stream conversion : \n");

		// 1. List of Integers
		List<Integer> numbers = Arrays.asList(
				10, 20, 30, 40, 50, 60, 70, 80, 90);

		// 1.1 collection to stream
		Stream<Integer> stream1 = numbers.stream();

		// 1.2 print to console using forEach()
		stream1.forEach(i -> System.out.println(i));


		System.out.println("\n2. List<String> to Stream conversion : \n");

		// 2. List of String
		List<String> names = Arrays.asList(
				"Vijay",
				"Vikram",
				"Ajith",
				"Suriya",
				"Karthi",
				"Dhanush",
				"Simbhu"
				);

		// 2.1 collection to stream and print to console

		names // original source
		.stream() // 1. get stream
		.forEach(i -> System.out.println(i)); // 3. terminal operation to print


		// 3. Names with length greater than 5 letters

		System.out.println("\n3. After Stream conversion,"
				+ " print names with length greater than 5 : \n");

		names // original source
		.stream() // 1. get stream
		.filter(name -> name.length() > 5) // 2. intermediate operation for filtering names
		.forEach(i -> System.out.println(i)); // 3. terminal operation to print to console
	}
}

Output:

1. List<Integer> to Stream conversion : 

10
20
30
40
50
60
70
80
90

2. List<String> to Stream conversion : 

Vijay
Vikram
Ajith
Suriya
Karthi
Dhanush
Simbhu

3. After Stream conversion, print names with length greater than 5 : 

Vikram
Suriya
Karthi
Dhanush
Simbhu

2.2 parallelStream() :

  • This method returns possibly parallel Stream for the invoking Collection like List/Set
  • Then we can apply chain of multiple intermediate operation, if required
  • Finally apply terminal operation to get result be it collecting to another List/Set or printing to console or counting, etc.
  • The advantage of parallel Stream over sequential Stream is that, it distributes work/process across multiple threads taking leverage of underlying multi-core processor for faster execution
  • Method signature :- default Stream parallelStream()
package net.bench.resources.stream.creation.example;

import java.util.ArrayList;
import java.util.List;

class Student {

	// member variables
	String name;
	int marks;

	// public no-arg constructor
	public Student(String name, int marks) {
		this.name = name;
		this.marks = marks;
	}
}


public class ParallelStreamExample {

	public static void main(String[] args) {

		// local variables
		long startTs;
		long endTs;
		long count;
		List<Student> studentList = getStudentList(); // student list

		// 1. Serial execution
		startTs = System.currentTimeMillis();

		count = studentList // original source
				.stream() // 1. get SERIAL stream
				.filter(s -> s.marks > 60) // 2. intermediate operation to filter wrt marks
				.count(); // 3. terminal operation to count after filtering

		System.out.println("1.1 Number students with marks more than 60 is : "
				+ count);

		endTs = System.currentTimeMillis();

		System.out.println("\n1.2 Time taken for Serial execution : "
				+ (endTs - startTs));


		// 1. parallel execution
		startTs = System.currentTimeMillis();

		count = studentList // original source
				.parallelStream() // 1. get PARALLEL stream
				.filter(s -> s.marks > 60) // 2. intermediate operation to filter wrt marks
				.count(); // 3. terminal operation to count after filtering

		System.out.println("\n\n2.1 Number students with marks more than 60 is : "
				+ count);

		endTs = System.currentTimeMillis();

		System.out.println("\n2.2 Time taken for Parallel execution : "
				+ (endTs - startTs));
	}

	/**
	 * Method to return list of Student
	 * @return
	 */
	public static List<Student> getStudentList() {

		// create List object
		List<Student> list = new ArrayList<Student>();

		// add few students for testing purpose
		list.add(new Student("Vijay", 97));
		list.add(new Student("Ajith", 82));
		list.add(new Student("Vikram", 77));
		list.add(new Student("Suriya", 65));
		list.add(new Student("Dhanush", 60));
		list.add(new Student("Arya", 48));
		list.add(new Student("Vishal", 35));

		// return list
		return list;
	}
}

Output:

1.1 Number students with marks more than 60 is : 4

1.2 Time taken for Serial execution : 75


2.1 Number students with marks more than 60 is : 4

2.2 Time taken for Parallel execution : 6

3. Difference between Sequential and parallel stream :

  • Sequential Stream :- It executes in single thread linearly or serially or sequentially
  • Parallel Stream :- It distributes work across multiple threads thereby leveraging the underlying multi-core processor of the system
  • Comparison :- When we compare these 2 execution mechanism in terms of time it taken to complete work, then parallel Stream possibly performs better than Sequential Stream
  • Execution time comparison :- As you can see in the above example, time taken to complete one unit of work with parallel stream is 6 ms whereas for same work sequential stream took 75 ms

References:

Happy Coding !!
Happy Learning !!

Java 8 - Stream filter method with examples
Java 8 - Introduction to Stream API