0% found this document useful (0 votes)
17 views5 pages

Java 8 Streams: Key Concepts & Examples

Uploaded by

rekha31182
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views5 pages

Java 8 Streams: Key Concepts & Examples

Uploaded by

rekha31182
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

# Java 8 Streams Notes

## Introduction
Java 8 introduced **Streams API** as a major feature to simplify data processing.
Before streams, developers relied heavily on loops, iterators, and the Collection
framework for traversing and manipulating data.
Streams provide a **declarative way** to work with data (what to do, not how to
do).

### Why Streams Were Introduced?


- To simplify **bulk operations** on collections (filtering, mapping, reducing).
- To provide **functional programming** style in Java (using lambdas).
- To enable **parallel execution** of operations with minimal effort.
- To reduce boilerplate code and improve **readability**.

### Benefits Over Collection Framework


1. **Declarative Style** – Focus on *what* to do rather than *how* (less
boilerplate code).
2. **Lazy Evaluation** – Operations are executed only when needed, improving
performance.
3. **Parallel Streams** – Easy to leverage multi-core processors
(`parallelStream()`).
4. **Functional Operations** – Support for `filter`, `map`, `reduce`, etc., which
are not present in normal collections.
5. **Chainable** – Multiple operations can be combined in a single pipeline.
6. **Cleaner Code** – Replaces nested loops and complex iteration logic.

### Key Points for Interview


- **Streams vs Collections**: Collections store data, Streams process data.
- **One-time use**: Streams cannot be reused after a terminal operation.
- **Parallel Streams**: Achieved via `parallelStream()`, can improve performance
for large datasets.
- **Intermediate vs Terminal Operations**:
- Intermediate (lazy): `filter`, `map`, `distinct`, `sorted`, `limit`, `skip`.
- Terminal: `collect`, `forEach`, `reduce`, `findFirst`, `findAny`, `count`.
- **Functional Interfaces**: Streams rely on `Predicate`, `Function`, `Consumer`,
and `Supplier`.
- **Best Practices**: Use streams for readability and performance, but avoid
overusing them where simple loops are sufficient.

---

## Stream Operations with Examples

### 1. filter()
Used to filter elements based on a condition.

```java
List<Employee> collect = asList
.stream()
.filter(t -> [Link]() > 10000)
.collect([Link]());

[Link](collect);
```

**Output:**
```
[Employee [name=Raj, id=2, salary=20000.0], Employee [name=Raj, id=3,
salary=30000.0]]
```

✅ Assignment: Filter employees whose names start with "R" and salary > 15000
💡 Use Case: Filtering active users from a database.

---

### 2. map()
Transforms elements.

```java
List<Double> collect = asList
.stream()
.map(t -> [Link]() + 5000)
.collect([Link]());

[Link](collect);
```

**Output:**
```
[15000.0, 25000.0, 35000.0]
```

✅ Assignment: Convert employee names to uppercase.


💡 Use Case: Extracting emails for notifications.

---

### 3. distinct()
Removes duplicates.

```java
List<Integer> collect = [Link](1,2,3,1,2,3)
.stream()
.distinct()
.collect([Link]());

[Link](collect);
```

**Output:**
```
[1, 2, 3]
```

✅ Assignment: Remove duplicate employee names.


💡 Use Case: Filtering unique product IDs.

---

### 4. findFirst() & findAny()


Fetches first or any element.

```java
Optional<Integer> first = [Link]().findFirst();
Optional<Integer> any = [Link]().findAny();
[Link]([Link]());
[Link]([Link]());
```

**Output:**
```
1
1 (or another element depending on execution)
```

✅ Assignment: Find lowest-paid employee using `findFirst`.


💡 Use Case: Fetch first available product in stock.

---

### 5. orElse()
Provides default if no value.

```java
Optional<Integer> result = [Link]()
.filter(t -> t > 100)
.findFirst();

[Link]([Link](10));
```

**Output:**
```
10
```

✅ Assignment: Return dummy employee if none earns above 50,000.


💡 Use Case: Avoid `NullPointerException`.

---

### 6. reduce()
Performs aggregation.

```java
Integer sum = [Link]()
.reduce((t, u) -> t + u)
.orElse(0);

[Link](sum);
```

**Output:**
```
6
```

✅ Assignment: Calculate total salary of employees.


💡 Use Case: Total sales from transactions.

---

### 7. flatMap()
Flattens nested collections.
```java
List<Double> collect = [Link]()
.flatMap(t -> [Link]())
.map(Employee::getSalary)
.collect([Link]());

[Link](collect);
```

**Output:**
```
[10000.0, 30000.0, 10000.0, 20000.0, 10000.0, 30000.0]
```

✅ Assignment: Get all employee names from multiple departments.


💡 Use Case: Flattening orders across customers.

---

### 8. sorted() & skip()


Sorting and skipping.

```java
Optional<Integer> result = [Link]()
.sorted()
.skip(2)
.findFirst();

[Link]([Link](0));
```

**Output:**
```
3
```

✅ Assignment: Get 2nd highest salary.


💡 Use Case: Data pagination.

---

### 9. Method References


Short-hand for lambdas.

```java
List<Integer> collect = [Link]()
.flatMap(t -> [Link]())
.map(Employee::getName)
.map(String::length)
.collect([Link]());

[Link](collect);
```

**Output:**
```
[3, 3, 3, 3, 3, 3]
```
✅ Assignment: Print only employee IDs using method reference.
💡 Use Case: Cleaner code in large projects.

---

## Conclusion
Streams in Java 8 provide a **powerful, concise, and efficient** way of processing
data. For interview preparation, remember:
- Difference between **Streams vs Collections**
- **Intermediate vs Terminal operations**
- **Parallel Streams**
- **Functional Interfaces**
- **Lazy Evaluation**
- **Common use cases** (filtering, mapping, reducing, flattening).

Mastering Streams will improve your **coding efficiency** and make your solutions
more **readable and scalable**.

Common questions

Powered by AI

Parallel streams are particularly beneficial in scenarios involving large datasets where operations can be distributed across multiple cores for faster execution. However, they come with potential risks, such as issues with thread safety and potential overhead from thread management, which can negate the performance benefits if used inappropriately for small datasets or for operations that do not benefit from parallelization .

The flatMap operation in Java 8 Streams is utilized to flatten nested collections into a single stream, simplifying actions such as extracting elements from nested structures. This is particularly useful in scenarios like aggregating data from multiple sub-collections, such as gathering all employee names from various departments for reporting. This operation enables seamless data integration and processing across complex models .

Method references offer a shorthand for lambda expressions, making code more concise and improving readability by reducing verbosity. When combined with Streams, this not only enhances the clarity and expressiveness of the code but also aids in easier maintenance, as method references directly denote call methods rather than using explicit lambda syntax, leading to cleaner and less error-prone code .

Intermediate operations in the Stream API such as filter, map, and distinct are lazy, meaning they are not executed until a terminal operation is invoked, allowing optimizations such as short-circuiting. Terminal operations like collect, forEach, and reduce trigger the execution of the operations on the stream and typically produce a result or a side-effect. This separation allows for efficient processing and combination of operations before final execution .

The Stream API supports a functional programming style in Java by introducing operations like filter, map, and reduce, which can be chained to process collections in a concise, declarative manner. This functional approach relies heavily on lambda expressions and functional interfaces such as Predicate, Function, and Consumer, leading to code that is more focused on what should be done and less on how it should be implemented, thus simplifying the structure and reducing boilerplate .

Lazy evaluation in Java Streams contributes to performance optimization by deferring the execution of operations until necessary, allowing the Streams to only process the data required by the terminal operation, thereby minimizing resource usage. This results in code that is more efficient as unnecessary computations are avoided, making scripts more responsive and capable of handling larger data sets with limited overhead .

The core difference is that a Collection in Java stores data, whereas a Stream processes data through a pipeline of operations. This distinction is crucial because Streams offer higher abstractions for operations, supporting functional-style operations without mutating data, improving code robustness and clarity by focusing on the transformation and processing of data elements rather than their storage .

Lazy evaluation allows Java Streams to process large datasets more efficiently by delaying operation execution until a terminal operation is reached, thus only performing the necessary computations. This contrasts with eager operations in collections, which require processing the entire data set upfront, potentially causing unnecessary computations and increased resource consumption. This lazy strategy thus enables handling of large or potentially infinite datasets without the need for large memory allocations .

Java 8 Streams improve performance and code clarity by allowing lazy evaluation, where intermediate operations are only performed as needed and can benefit from parallel processing to utilize multi-core processors easily. Additionally, the chainable and functional nature of Streams removes the need for complex iteration logic, resulting in cleaner and more readable code .

Java 8 Streams simplify bulk operations on collections by providing a declarative approach that allows developers to specify what operations should be carried out, rather than how to perform those operations. This is achieved through operations like filtering, mapping, and reducing, which replace the older imperative approach of using loops and iterators that required explicit iteration and traversal logic .

You might also like