I have introduced the Checker Framework v2.1.6 to a java8 project and have fixed all nullness errors but am stuck on the following error
Main.java:52: error: [assignment.type.incompatible] incompatible types in assignment.
List<String> collectedStrings = strings.stream().collect(Collectors.toList());
^
found : @Initialized @NonNull List<@Initialized @Nullable Object>
required: @UnknownInitialization @Nullable List<@Initialized @NonNull String>
The following (simplified) example code throws the error
List<String> strings = new ArrayList<>();
strings.add("test");
List<String> collectedStrings = strings.stream().collect(Collectors.toList());
collectedStrings.forEach(System.out::println);
Now I can work around this by making the result @Nullable
List<@Nullable String> collectedStrings = strings.stream().collect(Collectors.toList());
But this only cascades the error onto the next call which now thinks that collectedStrings is suspicious
Does anyone have a good work around for this?
The issue is that the Checker Framework assumes that Collectors.toList()
returns a List<@Nullable...>
. This is a safe, conservative assumption, but in your context you want List<@NonNull...>
. The Checker Framework's type inference is currently too weak to infer the type you want.
The cleanest way to solve the problem is by changing Collectors.toList()
to Collectors.<String>toList()
. (Writing just String
is equivalent to @NonNull String
.)
An alternative is to suppress the warning, writing @SuppressWarnings("nullness")
on the assignment.
The code below shows all these possibilities.
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.checkerframework.checker.nullness.qual.Nullable;
public class CollectorsToList {
void m(List<String> strings) {
Stream<String> s = strings.stream();
// This works:
List<String> collectedStrings1 = s.collect(Collectors.<String>toList());
// This works:
List<@Nullable String> collectedStrings2 = s.collect(Collectors.toList());
// This works:
@SuppressWarnings("nullness")
List<String> collectedStrings3 = s.collect(Collectors.toList());
// This assignment issues a warning due to incompatible types:
List<String> collectedStrings = s.collect(Collectors.toList());
collectedStrings.forEach(System.out::println);
}
}