DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Coding
  3. Java
  4. Process Collections Easily With Stream in Java 8

Process Collections Easily With Stream in Java 8

Learn how you can process collections easily with Stream in Java 8.

Leona Zhang user avatar by
Leona Zhang
·
Jul. 01, 19 · Tutorial
Like (30)
Save
Tweet
Share
44.77K Views

Join the DZone community and get the full member experience.

Join For Free

In Java, collections and arrays are two common data structures, on which many operations are regularly performed, including addition, deletion, modification, query, aggregate, statistics, and filtering. These operations also exist in relational databases. However, it is not very convenient to process collections and arrays before Java 8.

This problem is greatly alleviated in Java 8 by introducing a new abstraction called Stream API, which allows us to process data in a declarative manner. This article shows how to use Stream. Note that the performance and principles of Stream are not the central part of this article.

Stream Introduction

Stream provides a high-level abstraction for Java collection operations and expressions by querying data from databases similar to SQL statements.

Stream API can significantly improve the productivity of Java programmers and allow them write effective, clean, and concise code.

A collection of elements to be processed are considered as a stream, which is transmitted in a pipeline. These elements can be processed on nodes of the pipeline, such as filter, sort, and aggregate.

Characteristics and Advantages of Java Streams:

  • No storage. A Stream is not a data structure, but only a view of a data source, which can be an array, a Java container or an I/O channel.
  • A Stream is functional in nature. Any modifications to a Stream will not change the data sources. For example, filtering a Stream does not delete filtered elements, but generates a new Stream that does not contain filtered elements.
  • Lazy execution. Operations on a Stream will not be executed immediately. They will be executed only when users really need results.
  • Consumable. The elements of a stream are only visited once during the life of a stream. Once traversed, a Stream is invalidated, just like a container iterator. You have to regenerate a new Stream if you want to traverse the Stream again.

Let's use an example to see what a Stream can do:

Image title

The preceding example gets some plastic balls as the data source, filters the red ones, melts them down and converts them into random triangles. Another filter removes small triangles. A reducer sums up the circumferences

As shown in the preceding figure, a Stream involves three critical operations: stream creation, intermediate operations and terminal operations.

Stream Creation

In Java 8, many methods can be used to create a Stream.

1. Create a Stream by Using Existing Collections

In addition to many stream-related classes, Java 8 also enhances the collection class itself. The stream method in Java 8 can convert a collection into a Stream.

List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis", "Hello", "HelloWorld", "Hollis");
Stream<String> stream = strings.stream();


The preceding example creates a Stream from an existing List. In addition, the parallelStream method can create a parallel stream for a collection.

It is also very common to create a Stream from a collection.

2. Create a Stream by Using the Stream Method

The of method provided by Stream can be used to directly return a Stream consisting of specified elements.

Stream<String> stream = Stream.of("Hollis", "HollisChuang", "hollis", "Hello", "HelloWorld", "Hollis");


The preceding code creates and returns a Stream by using the of method.

Stream Intermediate Operations

A Stream may have many intermediate operations, which can be combined to form a pipeline. Each intermediate operation is like a worker on the pipeline. Each worker can process the Stream. intermediate operations return a new Stream.

Image title

The following is a list of common intermediate operations:

Image title

filter

The filter method is used to filter elements by specified conditions. The following code snippet uses the filter method to filter empty strings:

List<String> strings = Arrays.asList("Hollis", "", "HollisChuang", "H", "hollis");
strings.stream().filter(string -> ! string.isEmpty()).forEach(System.out::println);
//Hollis, , HollisChuang, H, hollis


map

The map method maps each elements to its corresponding result. The following code snippet use the map method to generate the square numbers of corresponding elements:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().map( i -> i*i).forEach(System.out::println);
//9,4,4,9,49,9,25


limit/skip

Limit returns the first N elements in a Stream. Skip abandons the first N elements in a Stream. The following code snippet uses the limit method to retain the first four elements:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().limit(4).forEach(System.out::println);
//3,2,2,3


sorted

The sorted method sorts elements in a Stream. The following code snippet uses the sorted method to sort Stream elements:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().sorted().forEach(System.out::println);
//2,2,3,3,3,5,7


distinct

The distinct method is used to remove duplicates. The following code snippet uses the distinct method to deduplicate elements:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().distinct().forEach(System.out::println);
//3,2,7,5


Next, we use an example and a figure to show what will happen to a Stream after performing operations filter, map, sort, limit, and distinct.

The following is the code:

List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis", "Hello", "HelloWorld", "Hollis");
Stream s = strings.stream().filter(string -> string.length()<= 6).map(String::length).sorted().limit(3)
            .distinct();


The following figure shows steps and the result for each step.

Image title

Stream Terminal Operations

Stream terminal operations also return a Stream. How can we convert a Stream into the desired type? For example, count elements in a Stream and convert that Stream into a collection. To do this, we need terminal operations.

A terminal operation will consume a Stream and generate a final result. That is to say, after a terminal operation is performed on a Stream, the Stream is not reusable and any intermediate operations are not allowed on that Stream. Otherwise, an exception is thrown:

java.lang.IllegalStateException: stream has already been operated upon or closed


This is the same as the meaning of the saying "You cannot step into the same river twice".

The following table lists the common terminal operations.

Image title

forEach

The forEach method iterates through elements in a Stream. The following code snippet uses forEach to return 10 random numbers:

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);


count

The count method counts the elements in a Stream.

List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis","Hollis666", "Hello", "HelloWorld", "Hollis");
System.out.println(strings.stream().count());
//7


collect

The collect operation is a reduce operation that can accept various parameters and accumulate the stream elements into a summary result:

List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis","Hollis666", "Hello", "HelloWorld", "Hollis");
strings  = strings.stream().filter(string -> string.startsWith("Hollis")).collect(Collectors.toList());
System.out.println(strings);
//Hollis, HollisChuang, Hollis666, Hollis


Next, we still use a figure to show the results of different terminal operations on the Stream given in the preceding example, on which filter, map, sort, limit, and distinct operations have been performed.

The following figure uses an example to show the input and output of all the operations described in this article.

Image title

Summary

This article explains the use and characteristics of Streams in Java 8. Stream creation, stream intermediate operations, and terminal operations are also described in this article.

We can use two methods to create a Stream: using the stream method of a Collection or using the of method of a Stream.

Stream intermediate operations can process Streams. Both the input and the output of intermediate operations are Streams. Intermediate operations include filter, map, and sort.

Stream terminal operations can convert a Stream into some other container, such as counting elements in a Stream, converting a Stream into a collection and iterating through elements in a Stream.



If you enjoyed this article and want to learn more about Java Streams, check out this collection of tutorials and articles on all things Java Streams.

Stream (computing) Java (programming language) Element

Published at DZone with permission of Leona Zhang. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Tackling the Top 5 Kubernetes Debugging Challenges
  • Cloud Performance Engineering
  • Choosing the Right Framework for Your Project
  • Configure Kubernetes Health Checks

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: