Filtering and mapping a stream effectively typically involves three main operations: filtering the elements that meet a specific condition, transforming the elements into another form (mapping), and processing them (e.g., collecting or printing). Here’s an explanation of how to do it effectively, based on the information provided (and generally applicable):
1. Filter
The filter method of a stream is used to remove elements that do not match a given condition. It takes a Predicate (a functional interface that returns true or false) as a parameter to test each element.
- Example: In
FilterStartWith.java, thefilter(s -> s.startsWith("c"))part ensures we only process elements of the list that start with"c".
package org.kodejava.util;
import java.util.Arrays;
import java.util.List;
public class FilterStartWith {
public static void main(String[] args) {
List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");
myList.stream()
.filter(s -> s.startsWith("c"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
}
}
2. Map
The map method transforms each element of the stream. It takes a Function (another functional interface that returns a value derived from the input).
- Example: In the same file, the
map(String::toUpperCase)part converts all filtered strings to their uppercase form.
3. Compose Operations
Streams are powerful because of their ability to compose multiple operations in a single pipeline. For example:
- Apply sequential filters.
- Transform elements after filtering.
- Sort and process the resulting stream.
-
Example from
FilterStartWith.java:
myList.stream() // Create a Stream from `myList` (source)
.filter(s -> s.startsWith("c")) // Keep elements starting with "c"
.map(String::toUpperCase) // Transform to upper case
.sorted() // Sort alphabetically
.forEach(System.out::println); // Print each resulting value
Output:
C1
C2
4. Optional Filtering
When working with Optional (like in FilterOptionalWithStream.java), you can use the filter method to conditionally process the value inside it. If the filter condition fails, the Optional becomes empty.
- The example given demonstrates effectively filtering an
Optional:
Optional<String> optional = Optional.of("hello");
optional.filter(value -> value.length() > 4)
.ifPresent(System.out::println); // Output: hello
Here:
filter(value -> value.length() > 4)ensures only strings with a length greater than 4 are processed.- Why
Optional.filterworks?: It’s a concise way to integrate filtering and avoid null checks manually.
package org.kodejava.util;
import java.util.Optional;
public class FilterOptionalWithStream {
public static void main(String[] args) {
Optional<String> optional = Optional.of("hello");
// Filter and process the value if it passes the condition
optional.filter(value -> value.length() > 4)
.ifPresent(System.out::println); // Output: hello
}
}
Remember These Best Practices
- Chain operations in logical order: Start with filtering, then followed by transformations (
map), and finally actions likeforEach,collect, etc. - Leverage method references: Simplify transformation and filtering logic with method references like
String::toUpperCaseor lambda expressions. - Use laziness: Streams are lazy — intermediate stages (e.g.,
filterormap) are run only when the terminal operation (likeforEach,collect, etc.) is called. - Immutable Stream Pipelines: Always treat streams as immutable; each intermediate operation produces a new stream without modifying the source.
Example Use Case: Combining filter and map
Here’s a general example illustrating filtering and mapping with streams:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
names.stream()
.filter(name -> name.length() > 3) // Keep names longer than 3 characters
.map(String::toUpperCase) // Convert them to uppercase
.sorted() // Sort alphabetically
.forEach(System.out::println); // Output each name
Output:
ALICE
CHARLIE
DAVID
Summary of Both Files Provided
- FilterOptionalWithStream.java
- Demonstrates effective filtering with
OptionalusingfilterandifPresent.
- Demonstrates effective filtering with
- FilterStartWith.java
- Shows a full pipeline: filtering, transforming with
map, sorting, and outputting the results withforEach.
- Shows a full pipeline: filtering, transforming with
Both represent excellent examples of leveraging the functional programming capabilities of streams in Java.
