typetools / typetools/checker-framework

Optional#orElse(null)

Open
#5,063 1 comment 0 reactions 1 assignee View on GitHub

@smillst is already working on this.

Since Feb 26, 2022.

Dominant language
Java
Stars
1.1k
Forks
440
Avg merge
1d 12h
Merged PRs (30d)
134

Description

Hello,
I am in the process of annotating one of my projects for nullness checking and am currently trying to resolve all the issues CheckerFramework complains about. I am using the Gradle plugin (v 0.6.8) to invoke the CheckerFramework (v 3.21.2).

One piece of code I am having trouble to get CheckerFramework to accept is of the following pattern:

List<? extends @NonNull String> list = new ArrayList<>(Arrays.asList("bla", "blubb")); // From somewhere out of my control, can be empty, String is an example type for reproduction, the actual code uses various other types
Stream<? extends @NonNull String> stream = list.stream(); // In some cases I also only get the Stream, instead of the underlying Collection
Optional<? extends @NonNull String> optional = stream.findFirst();
@Nullable String string = optional.orElse(null);

The goal is for the string variable to either hold the first value of the stream, or null if the stream is empty. This code gives me the following output:

[argument] incompatible argument for parameter other of orElse.

		@Nullable String string = optional.orElse(null);
		                                          ^
  found   : @UnknownKeyFor NullType

  required: capture#873[ extends @UnknownKeyFor String super @KeyForBottom Void]

I am having trouble to understand the issue here. Optional#orElse is marked as PolyNull in your annotated JDK, so I would have expected this to work. Is there a way to achieve what I want with Optional#orElse? A less elegant alternative might be for me to manually select a value based on Optional#isPresent.

I have also tried a few other variations of this code, all rejected by CheckerFramework by the same or different kinds of reasons.

List<? extends @NonNull String> list = new ArrayList<>(Arrays.asList("bla", "blubb")); // From somewhere out of my control, can be empty, String is an example type for reproduction, the actual code uses various other types
Stream<? extends @NonNull String> stream = list.stream();
Optional<? extends @NonNull String> optional = stream.findFirst();
@Nullable String string = optional.orElse((@Nullable String) null);
List<? extends @NonNull String> list = new ArrayList<>(Arrays.asList("bla", "blubb")); // From somewhere out of my control, can be empty, String is an example type for reproduction, the actual code uses various other types
Stream<? extends @NonNull String> stream = list.stream();
Optional<? extends @NonNull String> optional = stream.findFirst();
@Nullable String def = null;
@Nullable String string = optional.orElse(def);
List<? extends @NonNull String> list = new ArrayList<>(Arrays.asList("bla", "blubb")); // From somewhere out of my control, can be empty, String is an example type for reproduction, the actual code uses various other types
Stream<? extends @NonNull String> stream = list.stream();
Optional<? extends @NonNull String> optional = stream.findFirst();
@NonNull String def = "";
@Nullable String string = optional.orElse(def);
List<? extends @NonNull String> list = new ArrayList<>(Arrays.asList("bla", "blubb"));
Stream<? extends @NonNull String> stream = list.stream();
Optional<? extends @NonNull String> optional = stream.findFirst();
@NonNull String string = optional.orElse("");

The last one yields:

incompatible types: String cannot be converted to CAP#1
		@NonNull String string = optional.orElse("");
		                                         ^
  where CAP#1 is a fresh type-variable:
    CAP#1 extends @org.checkerframework.checker.nullness.qual.NonNull String from capture of ? extends @org.checkerframework.checker.nullness.qual.NonNull String

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.