Rule Proposal: Avoid Using Stream.toList()
if the List is Modified After Creation
1. Description of the Rule
Why is there an issue?
The Stream.toList()
method, introduced in Java 16, returns an unmodifiable list. If the returned list is modified (e.g., adding or removing elements), it results in an UnsupportedOperationException
at runtime.
What could be its impact?
- Bug Risk: Code that previously used
Collectors.toList()
(which returns a modifiable list) may break unexpectedly when refactored toStream.toList()
. - Runtime Errors: Any attempt to modify the list after its creation will cause an UnsupportedOperationException, leading to unexpected crashes.
- Maintainability Issue: Developers may unknowingly introduce immutable lists, leading to difficult-to-debug issues when modifications are later required.
What could happen in case of a successful attack?
This is not a security vulnerability, but it can cause production failures if the application logic depends on a mutable list.
2. Snippet of Noncompliant Code
java
CopyEdit
import java.util.List;
import java.util.stream.Stream;
public class Example {
public static void main(String[] args) {
List<String> names = Stream.of("Alice", "Bob", "Charlie").toList();
names.add("David"); // Throws UnsupportedOperationException at runtime
}
}
Exception Thrown:
cpp
CopyEdit
Exception in thread "main" java.lang.UnsupportedOperationException
3. Snippet of Compliant Code (Fixing the Above Noncompliant Code)
Option 1: Use Collectors.toList()
for a modifiable list
java
CopyEdit
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Example {
public static void main(String[] args) {
List<String> names = Stream.of("Alice", "Bob", "Charlie")
.collect(Collectors.toList());
names.add("David"); // No exception
}
}
Option 2: Wrap Stream.toList()
in a new ArrayList
to allow modifications
java
CopyEdit
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class Example {
public static void main(String[] args) {
List<String> names = new ArrayList<>(Stream.of("Alice", "Bob", "Charlie").toList());
names.add("David"); // Works fine
}
}
4. Exceptions to the Noncompliant Code
This rule should not raise an issue in cases where:
- The list is not modified after creation.
- The list is intentionally immutable for thread safety or functional programming reasons.
Example (Valid Use Case - No Modification):
java
CopyEdit
import java.util.List;
import java.util.stream.Stream;
public class Example {
public static void main(String[] args) {
List<String> names = Stream.of("Alice", "Bob", "Charlie").toList();
System.out.println(names); // Valid, no modification
}
}