0% found this document useful (0 votes)
4 views14 pages

Streams API Intermediate Operations

The document provides an overview of intermediate operations in the Java Stream API, including methods like filter(), map(), flatMap(), distinct(), and sorted(). Each operation is described with its purpose, syntax, and practical examples, emphasizing their lazy evaluation, chainability, and how they transform streams. Real-world use cases and comparisons to SQL operations are also included to illustrate the functionality of these methods.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views14 pages

Streams API Intermediate Operations

The document provides an overview of intermediate operations in the Java Stream API, including methods like filter(), map(), flatMap(), distinct(), and sorted(). Each operation is described with its purpose, syntax, and practical examples, emphasizing their lazy evaluation, chainability, and how they transform streams. Real-world use cases and comparisons to SQL operations are also included to illustrate the functionality of these methods.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

Stream API

End-to-End with Intermediate Operations

IP
ND
SA

​ ​ ​ ​ Notes By Sandip Vargale


Intermediate Operation
🔹 An intermediate operation is a method in the Java Stream API that transforms a
stream into another stream. It does not trigger processing of the data
immediately—instead, it builds up a pipeline of operations that will run later
when a terminal operation (like collect(), forEach(), etc.) is invoked..

🔹 Key Characteristics:
●​ Lazy Evaluation: Intermediate operations don’t do anything until a terminal
operation is called.
●​ Chainable: You can link multiple intermediate operations together (fluent
style).
●​ Return a Stream: They always return a new stream, allowing further operations.

Operations
🔹 1.filter()
✦ Purpose: Filters elements based on a predicate or given condition.​

IP
✦ Syntax: Stream<T> filter(Predicate<? super T> predicate)​

🔸 Example_1:

ND
List<String> names = Arrays.asList("John", "Jane", "Tom", "Jake");
​ ​ names.stream()
​ ​ .filter(name -> name.startsWith("J"))
​ ​ .forEach(System.out::println);

🔸 Example_2:​
SA

public class StreamExample {


​ ​ public static void main(String[] args) {
​ ​ ​ List<Integer> numbers = List.of(10, 15, 20, 25, 30);
​ ​ ​ List<Integer> evenNumbers = numbers.stream()
​ ​ ​ ​ ​ ​ ​ .filter(n -> n % 2 == 0)
​ ​ ​ ​ ​ ​ ​ .collect(Collectors.toList());
​ ​ ​ System.out.println(evenNumbers); // Output: [10, 20, 30]
​ ​ }
​ }

🔸 Example_3:

List<Integer> result = Stream.of(1, 3, 6, 8, 2, 5)
.filter(n -> n > 5)
.toList();
System.out.println(result); // Output: [6, 8]​

​ ​ ​ ​ Notes By Sandip Vargale


🧠 Real-time Use:
●​ Filtering out users whose names start with "J.
●​ Filtering out employees earning above a certain salary.

🔹 2.map()
​ ​ ​ ​ ​

✦ Purpose:
●​ The map() method is an intermediate operation in the Java Stream API.It is
used to transform (or map) each element of the stream from type T to
another type R.
●​ It returns a new stream consisting of the results of applying the given
Function to the elements of the original stream.

✦ Syntax: <R> Stream<R> map(Function<? super T, ? extends R> mapper)

► Breakdown of the Signature:
●​ <R> – This denotes a generic type of the result. It means that after

IP
mapping, each element in the new stream will be of type R.
●​ Function<? super T, ? extends R> – This is the functional interface used
to perform the transformation:
●​ T is the input type (type of elements in the original stream).
●​ R is the output type (type of elements in the resulting stream).
ND
●​ ? super T allows the function to accept T or any of its supertypes.
●​ ? extends R allows the result to be a subtype of R.

🔸 Example_1: Convert Strings to Uppercase
​ List<String> names = Arrays.asList("alice", "bob", "charlie");
SA

​ List<String> upperNames = names.stream()


​ ​ .map(String::toUpperCase) // Function<String, String>
​ ​ .toList();

​ System.out.println(upperNames); // [ALICE, BOB, CHARLIE]

► Note:
●​ String::toUpperCase is a function that takes a String and returns a
String.
●​ Here, T = String, R = String.

🔸 Example_2: Convert List of Strings to List of Lengths (Integer)
​ ​ List<String> names = Arrays.asList("apple", "banana", "kiwi");
​ ​
​ ​ List<Integer> nameLengths = names.stream()
​ ​ ​ .map(String::length) // Function<String, Integer>
​ ​ ​ .toList();
​ ​

​ ​ ​ ​ Notes By Sandip Vargale


​ ​ System.out.println(nameLengths); // [5, 6, 4]

► Note:
●​ This converts each String to its length.
●​ Here, T = String, R = Integer.

🔸 Example_3: Convert List of Objects to List of Fields

public class Employee {
String name;
int age;
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
}

IP
}

List<Employee> employees = Arrays.asList(
​ ​ new Employee("Alice", 30),
ND
​ ​ new Employee("Bob", 25)
);

List<String> employeeNames =
employees.stream()
​ ​ .map(Employee::getName) // Function<Employee, String>
​ ​ .collect(Collectors.toList());
SA


System.out.println(employeeNames); // [Alice, Bob]

🧠 Real-World Use Cases
●​ Transforming data before saving it to the database.
●​ Extracting specific fields from complex objects.
●​ Converting one data structure into another (e.g., DTO mapping).

🔹 3.flatMap()
✦ Purpose: Flattens nested structures/stream into a single stream.
​ flatMap() is a method in Java's Stream API that:
●​ Transforms each element in the stream into another stream (or collection).
●​ Then flattens all those nested streams into a single stream.
●​ In simple terms: map + flatten = flatMap

​ ​ ​ ​ Notes By Sandip Vargale


✦ Syntax:
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> m);
●​ Applies this function to each element of the original stream (type T),
●​ Gets multiple streams of R,
●​ Flattens those into one single stream of R.

🔸 Explanation
●​ For each element T in the original stream, apply a function that returns a
stream of R, then flatten all those streams into one stream of R."

🧠 Real-time Example:
●​ Extracting all subjects from multiple student records.
●​ Reading nested lists from JSON files and flattening them.
●​ Merging multiple lists of user roles into a single list.
​ ​ ​ ​ ​

🎯 Real-World Analogy (SQL vs flatMap)

IP
●​ Imagine a database with two tables: like having RelationShip (OneToMany)
One Departments can have multiple Employees ()or Many Employees belongs to
ND
One Department
​ ​ i.e
🗃️ Departments Tables 🗃️Employees Tables
id name id name dept_id

1 IT 1 Ram 1
SA

2 HR 2 Shyam 1

3 Seeta 2

​ ​
​ ​
🎯 SQL Query (Join with Flattened Result):
●​ SELECT d.name AS department, e.name AS employee
FROM Departments d
JOIN Employees e ON d.id = e.dept_id;
​ ​
●​ This query gives:

department employee

IT Ram

IT Ram

HR Seeta

​ ​ ​ ​ Notes By Sandip Vargale



► Note:
You joined departments with their employees and flattened all employee
lists into one single result set.

🔸 Java Equivalent Using flatMap


class Department {
​ String name;
​ List<Employee> employees;
​ // constructor, getter
}
​ ​
​ class Employee {
​ ​ String name;
​ ​ // constructor, getter
​ }

IP
🔸 Stream + flatMap Example:
​ ​
​ ​ List<Department> departments =
ND
new ArrayList<>(Arrays.asList(
​ ​ new Department("IT",
new ArrayList<>(Arrays.asList(new Employee("Ram"),
new Employee("Shyam")))),
​ ​ new Department("HR", new ArrayList<>(Arrays.asList(
new Employee("Seeta"))))
​ ​ ));
SA

​ ​
​ ​ departments.stream()
​ ​ ​ .flatMap(dept -> dept.getEmployees().stream())//flatten employee list
​ ​ ​ .map(Employee::getName) // get names only
​ ​ ​ .forEach(System.out::println);
🧾 Output:
Ram
Shyam
Seeta

🎨 Visual:
●​ Before flatMap: [ [Ram, Shyam],[Seeta] ]
●​ After flatMap: => [Ram, Shyam, Seeta]
​ ​
●​ Here, each department has its own list of employees (just like a subquery or
subtable).
●​ flatMap collects all these sublists into a single flattened stream — similar to
how SQL JOIN combines rows.

​ ​ ​ ​ Notes By Sandip Vargale
🧠 In Summary:
Concept SQL Java (Stream API)

Table Table / Row Object / Collection

Nested Data Subquery / JOIN List inside List (e.g.,


List<List<T>>)

Flattening Data JOIN or Subquery Result flatMap()

Transformation SELECT column map()

Combined SELECT + JOIN flatMap().map()

​ ​
► When to Use flatMap?
You have a stream of collections (e.g., List<List<String>>).
You want to combine them into a single stream before processing.

🔸 Example 1:

IP
List<List<String>> listOfLists = Arrays.asList(
​ Arrays.asList("apple", "banana"),
ND
​ ​ Arrays.asList("cherry", "date")
​ );
​ List<String> allItems = listOfLists.stream()
​ ​ ​ ​ ​ .flatMap(List::stream)
​ ​ ​ ​ ​ .toList();
​ System.out.println(allItems); // Output: [apple, banana, cherry, date]

🔸 Example 2:
SA

​ ​ List<List<String>> data = Arrays.asList(


​ ​ ​ Arrays.asList("a", "b"),
​ ​ ​ Arrays.asList("c", "d")
​ ​ );

​ ​ data.stream()
​ ​ ​ .flatMap(Collection::stream)
​ ​ ​ .forEach(System.out::println);​ ​
🔸 Example 3:

​ ​ List<String> sentences = Arrays.asList("hello world", "java streams");

​ ​ List<String> words = sentences.stream()


​ ​ ​ .flatMap(sentence -> Arrays.stream(sentence.split(" ")))
​ ​ ​ .collect(Collectors.toList());
​ ​
​ ​ System.out.println(words); [hello, world, java, streams]

​ ​ ​ ​ Notes By Sandip Vargale


🔹 4.distinct()
✦ Purpose: Removes duplicate elements ,distinct() works based on equals() and
hashCode() methods of your objects
✦ Syntax: Stream<T> distinct()

🔸 Example 1: Remove Duplicate Students

​ public class Student {
​ ​ private int id;
​ ​ private String name;
​ ​ // Constructor, Getters, Setters

​ ​ @Override
​ ​ public boolean equals(Object o) {
​ ​ ​ if (this == o) return true;
​ ​ ​ if (o == null || getClass() != o.getClass()) return false;

IP
​ ​ ​ Student student = (Student) o;
​ ​ ​ return id == student.id && Objects.equals(name, student.name);
​ ​ }

​ ​ @Override
ND
​ ​ public int hashCode() {
​ ​ ​ return Objects.hash(id, name);
​ ​ }
​ }
​ List<Student> students = Arrays.asList(
​​ ​ new Student(1, "Alice"),
​​ ​ new Student(2, "Bob"),
SA

​​ ​ new Student(1, "Alice") // duplicate


​ );

​ List<Student> uniqueStudents = students.stream()
​ ​ ​ ​ ​ ​ .distinct()
​ ​ ​ ​ ​ ​ .toList();
​ uniqueStudents.forEach(s -> System.out.println(s.getName()));

🔸 Example 2 : 💡 Alternative (Custom Uniqueness)
​ If you want to define "duplicate" based only on one field (like id), use a
custom collector or filter like:

List<Student> uniqueById =
students.stream()
.collect(Collectors.collectingAndThen(
Collectors.toMap(Student::getId, s -> s, (s1, s2) -> s1),
m -> new ArrayList<>(m.values())
));

​ ​ ​ ​ Notes By Sandip Vargale



​ This removes duplicates based only on the id.

🔸 Example 3 :
​ public class StreamExample {
​ ​ public static void main(String[] args) {
​ ​ ​ List<Integer> numbers = List.of(1, 2, 2, 3, 4, 4, 5);
​ ​ ​ List<Integer> uniqueNumbers =
numbers.stream()
​ ​ ​ ​ ​ .distinct()​​ ​ ​ ​ ​ ​
​ ​ .collect(Collectors.toList());
​ ​ ​ System.out.println(uniqueNumbers); // Output: [1, 2, 3, 4, 5]
​ ​ }
​ }

🧠 Real-World Use Case: Removing duplicate email addresses from a list.
🔹 5.sorted()
IP
✦ Purpose: Sorts the elements in natural order or using a comparator.
✦ Syntax:
ND
●​ Stream<T> sorted(); // Default Natural Sorting
●​ Stream<T> sorted(Comparator<? super T> comparator); // Customise Sorting
​ ​ ​
► Note : This sorts elements in natural order, which means:
●​ For numbers: ascending order (e.g., 1, 2, 3)
●​ For strings: lexicographic order (e.g., "apple", "banana", "zebra")
●​ For custom objects: the class must implement Comparable<T>
SA


🔸 Example 1 with integers:
​ ​ List<Integer> numbers = Arrays.asList(5, 1, 3);

​ ​ List<Integer> sorted = numbers.stream()
​ ​ ​ .sorted()
​ ​ ​ .collect(Collectors.toList());
​ ​
​ ​ System.out.println(sorted); // Output: [1, 3, 5]
​ ​
🔸 Example 2 : Stream<T> sorted(Comparator<? super T> comparator)
​ ​ This allows you to define a custom sort order using a Comparator.

​ ​ List<Student> students = Arrays.asList(
​ ​ new Student(1, "Bob"),
​ ​ new Student(2, "Alice"),
​ ​ new Student(3, "Charlie")
​ ​ );

​ ​ ​ ​ Notes By Sandip Vargale


​ ​
​ ​ List<Student> sortedByName = students.stream()
​ ​ ​ .sorted(Comparator.comparing(Student::getName))
​ ​ ​ .collect(Collectors.toList());
​ ​
​ ​ sortedByName.forEach(s -> System.out.println(s.getName()));
​ ​
🔸 Example 3: Custom Sorting of Students

​ ​ public class Student {
​ ​ private int id;
​ ​ private String name;
​ ​ private double gpa;

​ ​ // Constructor, Getters, Setters
​ ​ }
​ ​
🔸 Example 4:

Code with Collectors and custom sort:

IP
Sort students by GPA (highest first), then by name (A–Z)
ND
​ ​ List<Student> students = Arrays.asList(
​ ​ new Student(1, "Alice", 3.5),
​ ​ new Student(2, "Bob", 3.9),
​ ​ new Student(3, "Charlie", 3.9),
​ ​ new Student(4, "David", 3.2)
​ ​ );
​ ​
SA

​ ​ List<Student> sorted = students.stream()


​ ​ ​ .sorted(
​ ​ ​ Comparator.comparingDouble(Student::getGpa).reversed()
​ ​ ​ ​ ​ ​ .thenComparing(Student::getName)
​ ​ ​ )
​ ​ ​ .toList();
​ ​
​ ​ sorted.forEach(s -> System.out.println(s.getName() + " - " + s.getGpa()));

🧾 Output:
​ ​ ​ Bob - 3.9
​ ​ ​ Charlie - 3.9
​ ​ ​ Alice - 3.5
​ ​ ​ David - 3.2

🧠 Explanation:
●​ Comparator.comparingDouble(Student::getGpa).reversed() → sort by GPA descending
●​ thenComparing(Student::getName) → if GPAs are equal, sort by name ascending
●​ collect(Collectors.toList()) → collect the sorted stream into a list
​ ​ ​ ​ Notes By Sandip Vargale
🔸 Example 5: You Can Also Sort By:
​ .id → Comparator.comparing(Student::getId)
​ .name length → Comparator.comparingInt(s -> s.getName().length())
​ ​
🔸 Example 6:
​ List<String> names = Arrays.asList("John", "Alice", "Bob");
​ List<String> sortedNames = names.stream()
​ ​ ​ ​ ​ ​ ​ .sorted()
​ ​ ​ ​ ​ ​ ​ ..toList();
​ System.out.println(sortedNames); // Output: [Alice, Bob, John]
​ ​
🔸 Example 7:
​ Stream.of("banana", "apple", "cherry")
.sorted(Comparator.reverseOrder())
.forEach(System.out::println);​

🔹 6.peek()
​ without modifying the stream.

IP
✦ Purpose: Performs an action on each element as it is consumed from the stream ,

✦ Syntax: Stream<T> peek(Consumer<? super T> action)


ND
🔸 Example_1 :
​ ​ public class StreamExample {
​ ​ ​
public static void main(String[] args) {

​ ​ ​ ​ Stream.of("apple", "banana", "cherry")


SA

​ ​ ​ ​ ​ .peek(System.out::println)
​ ​ ​ ​ ​ .collect(Collectors.toList());
​ ​ ​ }
​ ​ }
​ ​
🔸 Example_2 :
​ ​ Stream.of("apple", "banana", "cherry")
​ ​ .peek(System.out::println)
​ ​ .map(String::toUpperCase)
​ ​ .forEach(System.out::println);

🧠 Real-World Use Case: Logging each transaction in a stream for debugging


purposes.
​ ​

​ ​ ​ ​ Notes By Sandip Vargale


🔹 7.limit(long maxSize)
✦ Purpose: Limits the number of elements in the stream.
✦ Syntax: Stream<T> limit(long maxSize)
🔸 Example 1:
​ ​ Stream.of(1, 2, 3, 4, 5)
​ ​ .limit(3)
​ ​ .forEach(System.out::println);

🧠 Real-time Use: Fetching only top 3 search results.
Displaying only the top 5 trending products.

🔹 8.skip(long n)
✦ Purpose: Skips the first N elements of the stream.
✦ Syntax: Stream<T> skip(long n);​
🔸 Example 1 :
​ List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

IP
​ List<Integer> skipped = numbers.stream()
.skip(3)
​ ​ ​ ​ ​ ​ .collect(Collectors.toList());
​ ​ ​ System.out.println(skipped); // Output: [4, 5, 6]
ND
​ ​
🧠 Real-World Use Case:
●​ Paginating through a list of records by skipping the first n items.
e.g. Implementing pagination (e.g., page 2 starts after skipping 10 elements).

🔹 9.mapToInt()
​ ​ ​

✦ Purpose: Converts elements to an IntStream. Specialized mapping for primitive


SA

types.
✦ Syntax: IntStream mapToInt(ToIntFunction<? super T> mapper);
🔸 Example :
​ ​ List<String> numbers = Arrays.asList("1", "2", "3");

​ ​ int sum = numbers.stream()


​ ​ ​ ​ ​ .mapToInt(Integer::parseInt)
​ ​ ​ ​ ​ .sum();
​ ​ System.out.println(sum); // Output: 6

🧠 Real-World Use Case: Calculating the total of a list of transaction amounts.


🔹 10.mapToLong()
​ ​

✦ Purpose : Converts elements to a LongStream.


✦ Syntax : LongStream mapToLong(ToLongFunction<? super T> mapper);
​ ​

​ ​ ​ ​ Notes By Sandip Vargale


🔸 Example:
​ ​ List<String> numbers = Arrays.asList("10000000000", "20000000000");
​ ​ long sum = numbers.stream()
​ ​ ​ ​ ​ .mapToLong(Long::parseLong)
​ ​ ​ ​ ​ .sum();

​ ​ System.out.println(sum); // Output: 30000000000


​ ​ ​
🧠 Real-World Use Case: Summing large transaction amounts in a financial
application.

🔹 11.mapToDouble()
✦ Purpose : Converts elements to a DoubleStream.
✦ Syntax : DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);

🔸 Example:

IP
​ ​ List<String> numbers = Arrays.asList("1.1", "2.2", "3.3");
​ ​ double average = numbers.stream()
​ ​ ​ ​ ​ .mapToDouble(Double::parseDouble)
​ ​ ​ ​ ​ .sum();

🔹
ND
What are IntStream, LongStream, and DoubleStream?
●​ They are specialized stream types in Java’s Stream API designed to work
efficiently with primitive data types: int, long, and double, respectively.

🔸 Why specialized streams?


●​ Regular streams like Stream<Integer> involve boxing and unboxing (wrapping
SA

primitives in objects), which adds overhead.


●​ Primitive streams avoid this by working directly with primitives, improving
performance and memory usage.

🔸 Example:
IntStream intStream = IntStream.of(1, 2, 3, 4);
int sum = intStream.sum(); // 10

LongStream longStream = LongStream.range(1, 5);


long max = longStream.max().orElse(0); // 4

DoubleStream doubleStream = DoubleStream.of(1.5, 2.5, 3.5);


double avg = doubleStream.average().orElse(0.0); // 2.5

​ ​ ​ ​ Notes By Sandip Vargale


IP
ND
SA

💡 Food for Thought!


If mapToInt() gives you an IntStream,​
👉 How would you convert it back into a Stream<Integer>?
💡 Hint: There's an intermediate method that does exactly this.

THANK YOU
​ ​ ​ ​ Notes By Sandip Vargale

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy