Java 8 Stream多条件过滤实现:可选参数动态过滤需求
Got it, this is a super common scenario—building a flexible filter that only applies conditions when the corresponding parameters are actually provided. Let’s break this down step by step with clean, readable Java 8 Stream code that fits your requirements perfectly.
First, let’s define a sample entity class we’ll work with (adjust field names or types if your actual data model differs):
import java.time.LocalDate; public class Record { private LocalDate createdDate; private String createdBy; private String intakeType; // Constructor, getters, setters, and toString() omitted for brevity }
Next, we’ll create a filtering method that handles all your optional parameters. We’ll start by handling date parsing (note: your input uses mm-dd-yyyy—if you meant month instead of minutes, swap mm for MM in the date formatter, since mm represents minutes in Java’s date pattern syntax):
import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.stream.Collectors; public class RecordFilterService { // Reusable thread-safe date formatter private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("MM-dd-yyyy"); public List<Record> filterRecords(List<Record> records, String createdFrom, String createdTo, String createdBy, List<String> intakeType) { return records.stream() // Filter by createdFrom (only if parameter is not null/blank) .filter(record -> { if (createdFrom == null || createdFrom.isBlank()) { return true; // Skip filter if parameter is missing } LocalDate fromDate = LocalDate.parse(createdFrom, DATE_FORMATTER); return !record.getCreatedDate().isBefore(fromDate); }) // Filter by createdTo (only if parameter is not null/blank) .filter(record -> { if (createdTo == null || createdTo.isBlank()) { return true; } LocalDate toDate = LocalDate.parse(createdTo, DATE_FORMATTER); return !record.getCreatedDate().isAfter(toDate); }) // Filter by createdBy (only if parameter is not null/blank) .filter(record -> { if (createdBy == null || createdBy.isBlank()) { return true; } // Use equalsIgnoreCase here if you want case-insensitive matching return createdBy.equals(record.getCreatedBy()); }) // Filter by intakeType list (only if list is not empty) .filter(record -> { if (intakeType == null || intakeType.isEmpty()) { return true; } return intakeType.contains(record.getIntakeType()); }) .collect(Collectors.toList()); } }
Key Details & Improvements:
- Conditional Filter Logic: Each filter lambda checks if the parameter is valid first. If the parameter is null/blank (for strings) or empty (for the list), we return
trueto let all records pass through that filter step. - Date Safety: We use Java 8’s
LocalDate(immutable and thread-safe) instead of legacyDateclasses. The formatter is a static final field to avoid recreating it on every method call. - Maintainability: For cleaner code (especially if your filter logic grows more complex), you can extract each filter into a separate method:
Then use these methods in your stream pipeline like:private Predicate<Record> createdFromFilter(String createdFrom) { if (createdFrom == null || createdFrom.isBlank()) { return r -> true; } LocalDate fromDate = LocalDate.parse(createdFrom, DATE_FORMATTER); return r -> !r.getCreatedDate().isBefore(fromDate); }return records.stream() .filter(createdFromFilter(createdFrom)) .filter(createdToFilter(createdTo)) .filter(createdByFilter(createdBy)) .filter(intakeTypeFilter(intakeType)) .collect(Collectors.toList()); - Flexibility: Adjust matching logic (like case-insensitive
createdBychecks) by tweaking the lambda expressions to fit your exact business needs.
内容的提问来源于stack exchange,提问作者RamKumar

