Вот код, который делает это.
import java.util.Objects;
import java.util.stream.Stream;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
class RemoveNullsFromStream {
@SuppressWarnings("nullness") // Nullness Checker is not hard-coded with
// implementation details of filter and Objects::nonNull
<T>
Stream<@NonNull T> removeNullsFromStream(Stream<@Nullable T> arg) {
return arg.filter(Objects::nonNull);
}
}
Обратите внимание на использование @SuppressWarnings
, потому что Nullness Checker консервативен: он выдает предупреждение, если он не может окончательно доказать, что код безопасности. В общем случае выход filter
совпадает с его входом; когда аргументом filter
является Objects::nonNull
- это особый случай.
Этот специальный корпус может быть жестко закодирован в Nullness Checker, и это сделает точность Nullness Checker более точной. В настоящее время это поведение не является специальным, поэтому вместо этого вы используете @SuppressWarnings
.
Благодарим за ответ. Но SuppressWarnings выглядят уродливо. Я попробовал arg.map (Необязательный :: fromNullable) .filter (Необязательный :: isPresent) .map (Необязательный :: get), но он по-прежнему возвращает список <@Nullable T>. Это ошибка CF? –
Для меня это длинное выражение выглядит хуже простого вызова 'removeNullsFromStream'. Поведение звуковое и консервативное: в общем случае 'filter' возвращает тот же тип, что и его аргумент. Подумайте, как вы знаете результат: «List <@Nullable>», а затем попытайтесь выразить шаги вашего аргумента в системе типов; если вы не можете, то '@ SuppressWarnings' по своей сути необходимо. – mernst
Как насчет arg.filter (Объекты :: nonNull) .map (t -> (@NonNull T) t) Почему он не создает поток <@NonNull T>? –