Techdozo
  • Microservices
    • All
    • GraphQL
    • gRPC
    • Spring Boot
    GraphQL Error Handling

    GraphQL Error Handling

    Pages

    Spring for GraphQL: Pagination with Code Example

    Spring for GraphQL: Interfaces and Unions

    gRPC Bidirectional Streaming with Code Example

    gRPC Bidirectional Streaming with Code Example

    gRPC Client Streaming

    gRPC Client Streaming

    Distributed transaction in microservices using Saga

    Distributed Transactions in Microservices: implementing Saga with Temporal

  • Spring Boot
    Pages

    Spring for GraphQL: Pagination with Code Example

    Spring Boot GraphQL service

    Getting started with Spring Boot GraphQL service

    Deploying a RESTful Spring Boot Microservice on Kubernetes

    Deploying a RESTful Spring Boot Microservice on Kubernetes

    RESTful Microservices with Spring Boot and Kubernetes

    RESTful Microservices with Spring Boot and Kubernetes

    RESTful API Gateway with gRPC

    RESTful API Gateway with gRPC

  • gRPC
    gRPC Bidirectional Streaming with Code Example

    gRPC Bidirectional Streaming with Code Example

    gRPC Client Streaming

    gRPC Client Streaming

    gRPC Interceptor: unary interceptor with code example

    gRPC Interceptor: unary interceptor with code example

    gRPC: synchronous and asynchronous Server streaming RPC

    gRPC: synchronous and asynchronous Server streaming RPC

    Photo by Ramón Salinero on Unsplash

    gRPC: synchronous and asynchronous unary RPC in Java

    Microservices inter-process communication using gRPC

    gRPC for microservices communication

  • GraphQL
    GraphQL Error Handling

    GraphQL Error Handling

    Pages

    Spring for GraphQL: Pagination with Code Example

    Spring for GraphQL: Interfaces and Unions

    GraphQL Directive

    GraphQL Directive

    Spring for GraphQL mutation

    Spring for GraphQL: Mutation

    Spring for GraphQL: How to solve the N+1 Problem?

    Spring for GraphQL: How to solve the N+1 Problem?

    Spring GraphQL with @Controller, @SchemaMapping and @QueryMapping

    Spring for GraphQL : @SchemaMapping and @QueryMapping

    Spring Boot GraphQL service

    Getting started with Spring Boot GraphQL service

  • Kubernetes
    Deploying a RESTful Spring Boot Microservice on Kubernetes

    Deploying a RESTful Spring Boot Microservice on Kubernetes

    Components of Kubernetes Architecture

    Components of Kubernetes Architecture

    Helm Chart: quick start your app deployment on Kubernetes

    Helm Chart: quick start your app deployment on Kubernetes

    gRPC load balancing on Kubernetes (using Headless Service)

    gRPC load balancing on Kubernetes (using Headless Service)

    Getting started with Kind: quick start a multi-node local Kubernetes cluster

    Getting started with Kind: quick start a multi-node local Kubernetes cluster

    Getting started with Minikube: deploying application on local Kubernetes cluster

    Getting started with Minikube: deploying application on local Kubernetes cluster

  • Java
    Java Streams: Stream Operation with Examples

    Java Streams: Stream Operation with Examples

    Java Streams: stream creation with examples

    Java Streams: stream creation with examples

    Garbage Collection

    Super Fast Garbage Collectors in Java

    Calculus

    Functional Programming in Java

No Result
View All Result
  • Login
  • Microservices
    • All
    • GraphQL
    • gRPC
    • Spring Boot
    GraphQL Error Handling

    GraphQL Error Handling

    Pages

    Spring for GraphQL: Pagination with Code Example

    Spring for GraphQL: Interfaces and Unions

    gRPC Bidirectional Streaming with Code Example

    gRPC Bidirectional Streaming with Code Example

    gRPC Client Streaming

    gRPC Client Streaming

    Distributed transaction in microservices using Saga

    Distributed Transactions in Microservices: implementing Saga with Temporal

  • Spring Boot
    Pages

    Spring for GraphQL: Pagination with Code Example

    Spring Boot GraphQL service

    Getting started with Spring Boot GraphQL service

    Deploying a RESTful Spring Boot Microservice on Kubernetes

    Deploying a RESTful Spring Boot Microservice on Kubernetes

    RESTful Microservices with Spring Boot and Kubernetes

    RESTful Microservices with Spring Boot and Kubernetes

    RESTful API Gateway with gRPC

    RESTful API Gateway with gRPC

  • gRPC
    gRPC Bidirectional Streaming with Code Example

    gRPC Bidirectional Streaming with Code Example

    gRPC Client Streaming

    gRPC Client Streaming

    gRPC Interceptor: unary interceptor with code example

    gRPC Interceptor: unary interceptor with code example

    gRPC: synchronous and asynchronous Server streaming RPC

    gRPC: synchronous and asynchronous Server streaming RPC

    Photo by Ramón Salinero on Unsplash

    gRPC: synchronous and asynchronous unary RPC in Java

    Microservices inter-process communication using gRPC

    gRPC for microservices communication

  • GraphQL
    GraphQL Error Handling

    GraphQL Error Handling

    Pages

    Spring for GraphQL: Pagination with Code Example

    Spring for GraphQL: Interfaces and Unions

    GraphQL Directive

    GraphQL Directive

    Spring for GraphQL mutation

    Spring for GraphQL: Mutation

    Spring for GraphQL: How to solve the N+1 Problem?

    Spring for GraphQL: How to solve the N+1 Problem?

    Spring GraphQL with @Controller, @SchemaMapping and @QueryMapping

    Spring for GraphQL : @SchemaMapping and @QueryMapping

    Spring Boot GraphQL service

    Getting started with Spring Boot GraphQL service

  • Kubernetes
    Deploying a RESTful Spring Boot Microservice on Kubernetes

    Deploying a RESTful Spring Boot Microservice on Kubernetes

    Components of Kubernetes Architecture

    Components of Kubernetes Architecture

    Helm Chart: quick start your app deployment on Kubernetes

    Helm Chart: quick start your app deployment on Kubernetes

    gRPC load balancing on Kubernetes (using Headless Service)

    gRPC load balancing on Kubernetes (using Headless Service)

    Getting started with Kind: quick start a multi-node local Kubernetes cluster

    Getting started with Kind: quick start a multi-node local Kubernetes cluster

    Getting started with Minikube: deploying application on local Kubernetes cluster

    Getting started with Minikube: deploying application on local Kubernetes cluster

  • Java
    Java Streams: Stream Operation with Examples

    Java Streams: Stream Operation with Examples

    Java Streams: stream creation with examples

    Java Streams: stream creation with examples

    Garbage Collection

    Super Fast Garbage Collectors in Java

    Calculus

    Functional Programming in Java

No Result
View All Result
Techdozo
No Result
View All Result
Home Java

Java Streams: Stream Operation with Examples

Pankaj by Pankaj
May 8, 2021
in Java
Reading Time: 15 mins read
0
A A
0
Java Streams: Stream Operation with Examples
ADVERTISEMENT
  • Share on Facebook
  • Share on Twitter
  • Share on Pinterest
  • Share on Linkedin
  • Share on Reddit

As we learned in Java Streams: stream creation with examples that a stream pipeline consists of a source, zero or more intermediate operations, and a terminal operation.

We also learned that streams are lazy; computation on the source data is only performed when the terminal operation is initiated.

ADVERTISEMENT

In this article, we are going to explore more about stream operation.

Stream Operation

Stream operations can be either intermediate or terminal. An intermediate operation produces another stream. Likewise, a terminal operation produces a result or side-effect.

Let’s take a look at some of the operations provides by the Java Stream.

Filtering a stream

You can filter a stream by passing a predicate (T -> boolean) to filter method. The filter is an intermediate operation that returns a filtered stream. If you are familiar with SQL, you can think of a predicate as a where clause.


List<Book> javaBooks =                                                                          
  books.stream()
  .filter(book -> book.getCategory().equals(JAVA))
  .collect(Collectors.toList());

Here stream of books is filtered based on the category. The predicate function is a lambda function book -> book.getCategory().equals(JAVA).

Take-While and Drop-While

Let’s say you need to find all the books whose price is less than $42. You can do something like:


List<Book> lessThan42 =                                                              
  books.stream()
  .filter(book -> book.getPrice() < 42)
  .collect(Collectors.toList());

One of the problems with the above approach is that filter iterates through the whole list even if the books are sorted. We can short-circuit the stream by using takeWhile as:

ADVERTISEMENT

List<Book> priceLessThan42 =                                                            
  books.stream()
  .takeWhile(book -> book.getPrice() < 42)
  .collect(Collectors.toList());

The takeWhile was introduced in Java 9.

Similarly, you can use dropWhile to drop the element of the stream which matches the given condition. This operation is the complement of takeWhile.


List<Book> priceGreaterThan42 =                                                            
  books.stream()
  .dropWhile(book -> book.getPrice() < 42)
  .collect(Collectors.toList());

The behavior of the takeWhile/dropWhile operation is nondeterministic if the stream is unordered, and some (but not all) elements of this stream match the given predicate. In this case, it can return any subset of matching elements including an empty stream.

Finding distinct element of a stream

The distinct() method returns a stream consisting of the distinct element by applying equals() method. This is a stateful intermediate operation.


List<String> publisher =                                                                    
  books.stream()
  .map(book -> book.getPublisher())
  .distinct()
  .collect(Collectors.toList());

Problem with Stateful Operation

A stream pipeline results may be nondeterministic or incorrect if function passed to the stream operations are stateful. A stateful operation is one whose result depends on any state which might change during the execution of the stream pipeline.

An example of a stateful lambda is the parameter to map() in:


Set<Integer> seen = Collections
  .synchronizedSet(new HashSet<>());

stream.parallel()
  .map(e -> { if (seen.add(e)) return 0; else return e; })...

Here, if the mapping operation is performed in parallel, the results for the same input could vary from run to run, due to thread scheduling differences. Whereas, with a stateless lambda expression the results would always be the same.

Truncating a stream

You can truncate a stream by short-circuiting stream by using limit operation on the stream. The limit is a stateful operation. It is a very cheap operation on a sequential stream. But, can be quite expensive on an ordered parallel stream.


books.stream().limit(2)
  .collect(Collectors.toList());

You can use skip(n) operation to discard the first n elements of a stream. Similar to limit, this can be quite an expensive operation on an ordered parallel pipeline.


books.stream().skip(2)
  .collect(Collectors.toList());

Mapping a Stream

You can map one stream to another stream using mapping functions.

Map

We can apply map function to transform one stream to another stream. For example, mapping Stream<Book> to Stream<String> of authors can be done as books.stream().map(Book::getAuthor). The result of map operation is another stream after applying the function (T) -> R on each element of the stream.


static List<String> mapToAuthors(List<Book> books) {               
  return books.stream()
  .map(Book::getAuthor)
  .collect(Collectors.toList()); 
}                                                                          

The function passed to the map operation should be non-interfering and stateless; otherwise, there can be undesired behavior with the possibility of code breaking in the future.

FlatMap

The flatMap operation applies a one-to-many transformation to a stream’s elements and flattens the resulting elements into a new stream.


<R> Stream<R> flatMap(Function<? super T
    , ? extends Stream<? extends R>> mapper);

Like map, the mapper function passed to the flatMap operation should be non-interfering and stateless.


Set<String> s = 
  Stream.of(set1, set2)
  .flatMap(Set::stream)
  .collect(Collectors.toSet());

The difference between map and flatMap operation is – map only applies transformation. Whereas, flatMap also flattens the stream.


static void flatMap() {

  List<Integer> primeNumbers = 
    Arrays.asList(2, 3, 5, 7, 11, 13);

  List<Integer> evenNumbers = 
    Arrays.asList(2, 4, 6, 8);

  List<List<Integer>> evenOrPrime = 
    Arrays.asList(primeNumbers, evenNumbers);

  List<Integer> numbers =
     evenOrPrime.stream()
    .flatMap(Collection::stream)
    .collect(Collectors.toList());

    log.info("Flattened map : {}", numbers);
  }

Above example prints – Flattened map : [2, 3, 5, 7, 11, 13, 2, 4, 6, 8]. As you can see, flatMap flattens a stream of List<Integer> to stream of Integer.

Mapping to primitive stream

A Stream<T> can be mapped to specialized primitive stream IntStream, DoubleStream and LongStream by calling methods mapToInt, mapToDouble, and mapToLong respectively.


static DoubleStream mapToPrice(List<Book> books) {  
  return books.stream()
  .mapToDouble(Book::getPrice);        
}                                                           

A specialized primitive stream can be converted back to a nonspecialized stream by calling boxed as:


static Stream<Double> box(DoubleStream doubleStream) { 
  return doubleStream.boxed();                                         
}                                                                      

Matching elements of the Stream

Stream class provides method to find matching elements in a stream. There are two types of method. One returns boolean, for example anyMatch. And another returns Optional, for example findAny.

Any Match

The anyMatch method returns true if any match for a given predicate is found. This is a short-circuiting terminal operation. This operation returns false for empty streams and stream is not evaluated.


static boolean hasAnyJavaBook(List<Book> books) {                            
  return books.stream()
  .anyMatch(book -> book.getCategory().equals(JAVA));
}                                                                                 

All Match

The allMatch method returns true when elements of the stream match given Predicate. This is a short-circuiting terminal operation. For an empty stream, this operation returns true and the stream is not evaluated.


static boolean hasAllJavaBook(List<Book> books) {                         
  return books.stream()
  .allMatch(book -> book.getCategory().equals(JAVA));
}                                                                                 

None Match

The noneMatch method returns true if no elements of the stream match given Predicate. This is a short-circuiting terminal operation. For an empty stream, this operation returns true and the stream is not evaluated.


static boolean hasNoJavaBook(List<Book> books) {                           
  return books.stream()
  .noneMatch(book -> book.getCategory().equals(JAVA));
}                                                                                  

Finding elements of the Stream

Find Any

The findAny method returns an Optional describing an arbitrary element of the stream, or an empty Optional if the stream is empty. This is a short-circuiting terminal operation. The behavior of this operation is nondeterministic; it can return any element of the stream.

The nondeterministic behavior allows for optimal performance in the case of a parallel stream.


static Optional<Book> findAnyJavaBook(List<Book> books) {                         
  return books.stream()
    .filter(book -> book.getCategory().equals(JAVA))
    .findAny();
}                                                                                         

The Optional<T> class (java.util.Optional) is a container object to represent the existence or absence of a value T. If findAny doesn’t find any element then it returns empty Optional instead of returning null.

Find First

The findFirst method returns an Optional which represents the first element of the stream, or an empty Optional if the stream is empty. If the stream has no encountered order then any element can be returned.


static Optional<Book> findFirstJavaBook(List<Book> books) {                          
  return books.stream()
    .filter(book -> book.getCategory().equals(Category.JAVA))
    .findFirst();
}                                                                                            

Finding the first element in a parallel stream is expensive. If you don’t care about which element is returned, we should use findAny.

Reduction Operation

A reduction operation (also called fold) takes a sequence of input elements and combines them into a single result by repeated application of combining operation. Stream classes have some generic reduction operations such as reduce() and collect(), and some specialized ones such as min(), max(),etc.

Reduce

The reduce method T reduce(T identity, BinaryOperator<T> accumulator) performs reduction operation on the stream using an associative accumulator function (BinaryOperator: T, U -> R) based on initial identity value. This is a terminal operation.


static double sum() {                                
  List<Integer> numbers = 
    List.of(1, 2, 3, 4, 5); 
          
  return numbers.stream()
  .reduce(0, (a, b) -> a + b);        
}                                                                                                                                          

or using method reference as:


private static double sum() {                             
  List<Integer> numbers = 
    List.of(1, 2, 3, 4, 5);         

  return numbers.stream()
  .reduce(0, Integer::sum);        
}                                                                                                                                

If a stream is empty then the identity (initial) value is returned. There is another variant of the reduce method ‘Optional<T> reduce(BinaryOperator<T> accumulator)‘ which returns Optional<T> (for an empty stream).

Min & Max

The reduce operation can be used to find min, max as:


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

Optional<Integer> min = 
  numbers.stream().reduce(Integer::min);

Optional<Integer> max = 
  numbers.stream().reduce(Integer::max);

Summary

Stream operations can be either intermediate or terminal. An intermediate operation produces another stream. Likewise, a terminal operation produces a result or side-effect.

  • You can use filter, distinct, takeWhile,dropWhile, skip, and limit method to filter and slice a stream.
  • You can transform elements of a stream using the ‘map‘ and ‘flatMap‘ method. The flatMap operation also flattens the stream.
  • You can find elements in a stream using findFirst and findAny method.
  • You can match a stream by using allMatch, anyMatch and anyMatch method for a given predicate.
  • You can combine elements of a stream using reduce.
Tags: functional programmingjavaJavaStream
Previous Post

Java Streams: stream creation with examples

Next Post

Deploying and accessing a microservices application in Kubernetes

Pankaj

Pankaj

Software Architect @ Schlumberger ``` Cloud | Microservices | Programming | Kubernetes | Architecture | Machine Learning | Java | Python ```

Related Posts

Java Streams: stream creation with examples
Java

Java Streams: stream creation with examples

May 1, 2021
Garbage Collection
Java

Super Fast Garbage Collectors in Java

September 14, 2020
Calculus
Java

Functional Programming in Java

September 7, 2020

Discussion about this post

Recent Articles

GraphQL Error Handling

GraphQL Error Handling

August 9, 2023
Pages

Spring for GraphQL: Pagination with Code Example

July 26, 2023

Spring for GraphQL: Interfaces and Unions

May 17, 2023
gRPC Bidirectional Streaming with Code Example

gRPC Bidirectional Streaming with Code Example

February 17, 2023
  • Trending
  • Comments
  • Latest
gRPC Bidirectional Streaming with Code Example

gRPC Bidirectional Streaming with Code Example

February 17, 2023
Deploying a RESTful Spring Boot Microservice on Kubernetes

Deploying a RESTful Spring Boot Microservice on Kubernetes

August 18, 2021
gRPC Interceptor: unary interceptor with code example

gRPC Interceptor: unary interceptor with code example

April 30, 2022
Temporal Workflow Orchestration

Workflow Orchestration with Temporal and Spring Boot

October 29, 2022
Calculus

Functional Programming in Java

0
Java Streams: stream creation with examples

Java Streams: stream creation with examples

0
Garbage Collection

Super Fast Garbage Collectors in Java

0
Java Streams: Stream Operation with Examples

Java Streams: Stream Operation with Examples

0
GraphQL Error Handling

GraphQL Error Handling

August 9, 2023
Pages

Spring for GraphQL: Pagination with Code Example

July 26, 2023

Spring for GraphQL: Interfaces and Unions

May 17, 2023
gRPC Bidirectional Streaming with Code Example

gRPC Bidirectional Streaming with Code Example

February 17, 2023
Facebook Twitter Pinterest

TECHDOZO

Simplifying modern tech stack!

Browse by Category

  • Bitesize
  • GraphQL
  • gRPC
  • Java
  • Kubernetes
  • Microservices
  • Spring Boot

Recent Articles

GraphQL Error Handling

GraphQL Error Handling

August 9, 2023
Pages

Spring for GraphQL: Pagination with Code Example

July 26, 2023

© 2023 Techdozo.

Welcome Back!

Sign In with Google
OR

Login to your account below

Forgotten Password?

Retrieve your password

Please enter your username or email address to reset your password.

Log In
No Result
View All Result
  • Home
  • gRPC
  • Kubernetes
  • Microservices
  • GraphQL

© 2023 Techdozo.