在使用 @EnsuresNonNullIf验证方法时出现的空指针解引用错误

编程语言 2026-07-11

NullAway在下面这段代码中的 place.getGeographicLocation().getValue().getGeoJson().getCoordinates() 链的所有部分都报告了解引用错误,尽管它已经通过传递给 hasValidGeoJsonCoordinates 进行验证。我在验证方法中添加了 @EnsuresNonNullIf 注释,但似乎并不起作用。这是一个缺陷吗?还是对NullAway来说太复杂,无法处理?

Using ErrorProne 2.48.0、Nullaway 0.13.1、Java 21

private @Nullable String getCoordinate(int index) {
        return getPlaces().stream()
            .filter(this::hasValidGeoJsonCoordinates)
            .map(place -> place.getGeographicLocation().getValue().getGeoJson().getCoordinates().get(index))
            .filter(Objects::nonNull)
            .map(Object::toString)
            .findFirst()
            .orElse(null);
    }

    @EnsuresNonNullIf(expression = {"#1", "#1.geographicLocation", "#1.geographicLocation.value", "#1.geographicLocation.value.geoJson", "#1.geographicLocation.value.geoJson.coordinates"}, result = true)
    private boolean hasValidGeoJsonCoordinates(@Nullable Place place) {
        return nonNull(place)
            && nonNull(place.getGeographicLocation())
            && nonNull(place.getGeographicLocation().getValue())
            && nonNull(place.getGeographicLocation().getValue().getGeoJson())
            && isNotEmpty(place.getGeographicLocation().getValue().getGeoJson().getCoordinates())
            && place.getGeographicLocation().getValue().getGeoJson().getCoordinates().size() > 1;
    }

解决方案

NullAway的记忆力有点短。

当你使用一个 Stream 时,NullAway会把 filtermap 当作两个彼此不交谈的人。尽管 filter 已证明数据是安全的,map 仍然没收到这条信息。

使用for循环。将所有逻辑都放在一个块中时,NullAway在跟踪逻辑方面要好得多。

private @Nullable String getCoordinate(int index) {
    for (Place place : getPlaces()) {
        if (hasValidGeoJsonCoordinates(place)) {
            // NullAway "sees" the check here and stays quiet
            return place.getGeographicLocation().getValue().getGeoJson().getCoordinates().get(index);
        }
    }
    return null;
}

如果你一定要在Stream中继续,可以把所有那些“获取”逻辑放在检查之后的单个 .map().flatMap() 里面,这样NullAway就不会丢失线索。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章