如何用Java 8 Stream、过滤器及Lambda筛选符合条件的CSV行
Hey there! Let's walk through solving both of your CSV filtering problems using Java 8's Streams API, Lambdas, and filters. I'll break down each requirement with code examples and clear explanations.
This task requires us to keep any row that has 0 or 1 empty columns (after trimming whitespace, to handle cases where a column is just spaces). Here's how to implement it:
import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; public class CsvSingleEmptyColumnFilter { public static void main(String[] args) { String csvFilePath = "path/to/your/csv/file.csv"; try { Files.lines(Paths.get(csvFilePath)) .skip(1) // Skip the header row (column names) .map(line -> line.split("\\s+")) // Split row into columns; use "," for standard comma-separated CSV .filter(columns -> { // Count how many columns are empty after trimming long emptyColumnCount = Arrays.stream(columns) .map(String::trim) .filter(String::isEmpty) .count(); // Keep rows with 0 or 1 empty columns return emptyColumnCount <= 1; }) .forEach(filteredRow -> System.out.println(String.join(" ", filteredRow))); } catch (IOException e) { System.err.println("Error reading CSV file: " + e.getMessage()); e.printStackTrace(); } } }
Key Notes:
Files.lines()gives us a stream of each line in the CSV file, which is efficient for large files.skip(1)skips the header row (since we don't want to filter the column names).split("\\s+")splits the row into columns using whitespace as the separator. If your CSV uses commas, replace this withsplit(",").- We trim each column before checking if it's empty to avoid counting columns with just spaces as empty.
For this task, we only care that columns B through F (indices 1 to 5, since ColumnA is index 0) have non-empty values. ColumnA can be empty or not. Here's the implementation:
import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; public class CsvBToFNonEmptyFilter { public static void main(String[] args) { String csvFilePath = "path/to/your/csv/file.csv"; try { Files.lines(Paths.get(csvFilePath)) .skip(1) // Skip header row .map(line -> line.split("\\s+")) // Split into columns; adjust separator if needed .filter(columns -> { // First, ensure we have at least 6 columns (A-F) to avoid index errors if (columns.length < 6) { return false; } // Check that columns 1 to 5 (B-F) are all non-empty after trimming return Arrays.stream(columns, 1, 6) // Stream from index 1 (inclusive) to 6 (exclusive) .map(String::trim) .noneMatch(String::isEmpty); }) .forEach(filteredRow -> System.out.println(String.join(" ", filteredRow))); } catch (IOException e) { System.err.println("Error reading CSV file: " + e.getMessage()); e.printStackTrace(); } } }
Key Notes:
Arrays.stream(columns, 1, 6)lets us directly stream only the columns we care about (B to F) without processing all columns.noneMatch(String::isEmpty)ensures that none of the columns in B-F are empty after trimming. This is a concise way to check all elements meet a condition.- We add a check for
columns.length <6to avoidArrayIndexOutOfBoundsExceptionif a row has fewer than 6 columns (since that would mean at least one of B-F is missing).
A Quick Note on CSV Parsing
For production code, I'd recommend using a dedicated CSV parser like OpenCSV instead of splitting strings directly. This handles edge cases like quoted fields containing commas or spaces, which simple splitting can't handle correctly. But for the given example, splitting by whitespace works perfectly.
内容的提问来源于stack exchange,提问作者Ankit

