Keywords: Java | Array Filtering | Stream API
Abstract: This article delves into multiple methods for removing empty strings ("") and null values from string arrays in Java, focusing on modern solutions using Java 8 Stream API and traditional List-based approaches. By comparing performance and use cases, it provides complete code examples and best practices to help developers efficiently handle array filtering tasks.
Introduction and Problem Context
In Java programming, handling string arrays containing empty strings or null values is a common requirement. For example, given an array String[] firstArray = {"test1", "", "test2", "test4", "", null};, the goal is to extract non-empty and non-null elements into a new array {"test1", "test2", "test4"}. This article systematically analyzes various implementation strategies from core concepts.
Core Concepts: Distinguishing Empty Strings and Null
First, clarify two key concepts: an empty string ("") is a valid String object instance with its length() method returning 0; whereas null indicates a reference pointing to no object, and invoking its methods causes NullPointerException. When filtering, check both s != null and s.length() > 0 to avoid exceptions and exclude empty values.
Traditional Approach: Using ArrayList
Prior to Java 8, ArrayList is commonly used to dynamically store filtered elements. Basic steps include: initialize an ArrayList, iterate through the original array, add valid elements via conditional checks, and finally convert back to an array. Example code:
import java.util.ArrayList;
import java.util.List;
public class RemoveNullValue {
public static void main(String[] args) {
String[] firstArray = {"test1", "", "test2", "test4", "", null};
List<String> list = new ArrayList<String>();
for (String s : firstArray) {
if (s != null && s.length() > 0) {
list.add(s);
}
}
firstArray = list.toArray(new String[list.size()]);
}
}This method is straightforward but requires manual list management, making the code slightly verbose.
Modern Approach: Optimization with Java 8 Stream API
The Stream API introduced in Java 8 offers a more concise functional programming style. Use Arrays.stream() to convert the array to a stream, combine with filter() for conditional filtering, and collect results with toArray(). Core code:
import java.util.Arrays;
public class RemoveNullValue {
public static void main(String[] args) {
String[] firstArray = {"test1", "", "test2", "test4", "", null};
firstArray = Arrays.stream(firstArray)
.filter(s -> s != null && s.length() > 0)
.toArray(String[]::new);
}
}This approach yields more compact code, improves readability with lambda expressions, and parallel streams can optimize large dataset processing.
Supplementary Solutions and Utility Methods
Beyond the above methods, Objects.nonNull can filter null values but requires additional handling for empty strings. For instance: Arrays.stream(firstArray).filter(Objects::nonNull).toArray(String[]::new); removes only nulls, retaining empty strings. To handle both, define a utility method:
public static boolean isNotEmpty(String str) {
return str != null && !str.isEmpty();
}
// Usage: Arrays.stream(firstArray).filter(ClassName::isNotEmpty).toArray(String[]::new);Additionally, Apache Commons Lang library's StringUtils.isNotEmpty() provides similar functionality, reducing code duplication.
Performance and Use Case Analysis
For small arrays, the traditional ArrayList method is performant enough and widely compatible (supporting earlier Java versions). The Stream API excels in code conciseness and maintainability, suitable for modern Java projects, with parallel processing accelerating large-scale data filtering. In practice, choose based on project environment, team preferences, and performance requirements.
Conclusion and Best Practices
To remove empty and null values from string arrays, it is recommended to use Java 8 Stream API with conditional filtering for efficient and readable code. Key steps include: correctly distinguishing null from empty strings, using filter(s -> s != null && s.length() > 0) for compound checks, and integrating utility methods as needed. Through this analysis, developers can flexibly apply these techniques to enhance array processing capabilities.