eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

eBook – Java Streams – NPI (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Java Concurrency – NPI (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

1. Introduction

In this tutorial, we’re going to explore Collections.parallelStream() and stream().parallel() offerings of Java Streams API. Java introduced the parallelStream() method to the Collection interface and the parallel() method to the BaseStream interface with Java 8. 

2. Parallel Stream and Parallelism in Java

A parallel stream allows us to use multi-core processing by executing the stream operation parallel across multiple CPU cores. The data is split into multiple sub-streams, and the intended operation is performed in parallel, and finally, the results are aggregated back to form the final output. 

A stream created in Java is always serial in nature by default unless specified otherwise. We can convert the stream to a parallel stream in two ways: 

  • we can invoke Collections.parallelStream()
  • we can invoke BaseStream.parallel()

If not specified by the stream operation, the Java compiler and runtime decide the sequence of processing for optimal parallel computing benefits when a parallel stream operation is executed.

For example, we are provided with a very long list of Book objects. We have to determine the count of books that were published in a specified year:

public class Book {
    private String name;
    private String author;
    private int yearPublished;
    
    // getters and setters
}

We can leverage parallel streams here and find the count more efficiently than doing it serially. The order of execution in our example does not impact the final result in any way, making it a perfect candidate for parallel Stream operation. 

3. Usage of Collections.parallelStream() 

One of the ways we can use parallel streams in our application is by invoking parallelStream() on the data source. This operation returns a possibly parallel Stream with the collection offered as its source. We can apply this to our example and find the count of books published in a specific year:

long usingCollectionsParallel(Collection<Book> listOfbooks, int year) {
    AtomicLong countOfBooks = new AtomicLong();
    listOfbooks.parallelStream()
      .forEach(book -> {
          if (book.getYearPublished() == year) {
              countOfBooks.getAndIncrement();
          }
      });
    return countOfBooks.get();
}

The default implementation of the parallelStream() method creates a parallel Stream from the Collection‘s Spliterator<T> interface. The Spliterator is an object for traversing and partitioning elements of its source. A Spliterator can partition off some of the elements of its source using its trySplit() method to make it eligible for possible parallel operations.

The Spliterator API, similar to an Iterator, allows for the traversal of elements of its source and was designed to support efficient parallel traversal. The Collection‘s default Spliterator will be used in parallelStream() invocation. 

4. Usage of parallel() on a Stream   

We can achieve the same result by first converting the collection to a Stream. We can convert the sequential stream generated as a result into a parallel Stream by calling parallel() on it. Once we have a parallel Stream, we can find our result in the same way we have done above:

long usingStreamParallel(Collection<Book> listOfBooks, int year) {
    AtomicLong countOfBooks = new AtomicLong();
    listOfBooks.stream().parallel()
      .forEach(book -> {
          if (book.getYearPublished() == year) {
              countOfBooks.getAndIncrement();
          }
      });
    return countOfBooks.get();
}

The Streams API’s BaseStream interface will split the underlying data as much as the source collection’s default Spliterator will allow and then use the Fork-Join framework to convert it into a parallel Stream. 

The result of both approaches bears the same result. 

5. Difference in parallelStream() and stream().parallel()

Collections.parallelStream() uses the source collection’s default Spliterator to split the data source to enable parallel execution. Splitting the data source evenly is important to enabling correct parallel execution. An unevenly split data source does more harm in parallel execution than its sequential counterpart.

We have been using List<Book> to hold our list of books in all these examples. Let’s now try to create a custom Collection for our Books by overriding the Collection<T> interface. 

We should remember that overriding an interface means we would have to provide our implementation of the abstract methods defined in the base interface. However, we see that methods such as spliterator(), stream(), and parallelStream() are present as default methods in the interface. These methods have an implementation provided by default. However, we can override those implementations with our versions nonetheless.

We’ll call our custom Collection for Books, MyBookContainer and we’ll define our own Spliterator as well: 

public class BookSpliterator<T> implements Spliterator<T> {
    private final Object[] books;
    private int startIndex;
    public BookSpliterator(Object[] books, int startIndex) {
        this.books = books;
        this.startIndex = startIndex;
    }
    
    @Override
    public Spliterator<T> trySplit() {
        // Always Assuming that the source is too small to split, returning null
        return null;
    }

    // Other overridden methods such as tryAdvance(), estimateSize() etc
}

In the above code snippet, we see that our version of the Spliterator takes in an array of Objects(in our case, Book) to split, and in the trySplit() method, it always returns null. 

We should note that this implementation of the Spliterator<T> interface is error-prone and does not partition the data into equal parts; instead returns null, resulting in unbalanced data. This is simply for representation purposes.

We will use this Spliterator in our custom Collection class MyBookContainer

public class MyBookContainer<T> implements Collection<T> {
    private static final long serialVersionUID = 1L;
    private T[] elements;

    public MyBookContainer(T[] elements) {
        this.elements = elements;
    }

    @Override
    public Spliterator<T> spliterator() {
        return new BookSpliterator(elements, 0);
    }

    @Override
    public Stream<T> parallelStream() {
        return StreamSupport.stream(spliterator(), false);
    }
    
    // standard overridden methods of Collection Interface
}

We’ll try to store data in our custom container class and perform parallel Stream operations on it:

long usingWithCustomSpliterator(MyBookContainer<Book> listOfBooks, int year) {
    AtomicLong countOfBooks = new AtomicLong();
    listOfBooks.parallelStream()
      .forEach(book -> {
          if (book.getYearPublished() == year) {
              countOfBooks.getAndIncrement();
          }
      });
    return countOfBooks.get();
}

The data source in this example is an instance of the MyBookContainer type. This code internally uses our custom Spliterator to split the data source. The resultant parallel Stream will be a sequential stream at best. 

We just exploited the parallelStream() method to return a sequential stream, even though the name suggests parallelStream. This is where the method differs from stream().parallel(), which always tries to return a parallel version of the stream provided to it. Java has documented this behavior in its documentation as follows:

@implSpec
 * The default implementation creates a parallel {@code Stream} from the
 * collection's {@code Spliterator}.
  *
  * @return a possibly parallel {@code Stream} over the elements in this
  * collection
 * @since 1.8
  */
default Stream<E> parallelStream() {
    return StreamSupport.stream(spliterator(), true);
}

6. Conclusion

In this article, we covered the ways we can create parallel Streams from a Collection data source. We also tried to find out the difference between parallelStream() and stream().parallel() by implementing our custom versions of a Collection and Spliterator. 

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook – Java Streams – NPI (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Java Concurrency – NPI (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook Jackson – NPI EA – 3 (cat = Jackson)