代码之家  ›  专栏  ›  技术社区  ›  Heath Borders

防止Android Studio检查从标记Java流链中包含可能的NulpPoExExcExchange

  •  2
  • Heath Borders  · 技术社区  · 6 年前

    我正在编写一个实用方法来提取包装的不可分割对象的数组:

    public interface UnparcelableHolder<U> {
        @Nullable U getUnparcelable();
    }
    
    public final class FragmentUtil {
        @Nullable
        public static <U> List<U> getUnparcelableHolderListArgument(
                @Nonnull Fragment fragment,
                @Nonnull Class<UnparcelableHolder<U>> unparcelableHolderClass,
                @Nonnull String key
        ) {
            @Nullable final Bundle arguments = fragment.getArguments();
            if (arguments == null) {
                return null;
            } else {
                @Nullable final Parcelable[] parcelableArray = arguments.getParcelableArray(key);
                if (parcelableArray == null) {
                    return null;
                } else {
                    return Arrays
                            .stream(parcelableArray)
                            .filter(unparcelableHolderClass::isInstance)
                            .map(unparcelableHolderClass::cast)
                            .filter(Objects::nonNull)
                            .map(UnparcelableHolder::getUnparcelable)
                            .filter(Objects::nonNull)
                            .collect(Collectors.toList());
                }
                if (unparcelableHolderClass.isInstance(parcelable)) {
                    @Nonnull final UnparcelableHolder<U> unparcelableHolder =
                            Objects.requireNonNull(unparcelableHolderClass.cast(parcelable));
                    return unparcelableHolder.getUnparcelable();
                } else {
                    return null;
                }
            }
        }
    }
    

    安卓工作室警告我 .map(UnparcelableHolder::getUnparcelable) 呼叫可能导致 NullPointerException . 这不可能,因为我之前 filter(Objects::nonNull) 打电话。如何告诉Android Studio的检查器我的代码是干净的?

    这是一个 MCVE is available on github 使用Android Studio 3.4 Beta 2构建:

    build.gradle :

    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 28
        defaultConfig {
            applicationId "com.github.hborders.streamsnonnulljsr305"
            minSdkVersion 28
            targetSdkVersion 28
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
        compileOptions {
            sourceCompatibility = '1.8'
            targetCompatibility = '1.8'
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'com.android.support:appcompat-v7:28.0.0'
        implementation 'com.android.support.constraint:constraint-layout:1.1.3'
        implementation 'com.google.code.findbugs:jsr305:3.0.2'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    }
    

    MainActivity.java :

    package com.github.hborders.streamsnonnulljsr305;
    
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.Objects;
    import java.util.stream.Collectors;
    
    import javax.annotation.Nonnull;
    import javax.annotation.Nullable;
    
    public class MainActivity extends AppCompatActivity {
    
        class Foo {
            @Nonnull
            private final String string;
    
            Foo(@Nonnull String string) {
                this.string = string;
            }
    
            @Nonnull
            String getString() {
                return string;
            }
        }
    
        class Bar {
            @Nullable
            private final Foo foo;
    
            Bar(@Nullable Foo foo) {
                this.foo = foo;
            }
    
            @Nullable
            Foo getFoo() {
                return foo;
            }
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            final Bar bar1 = new Bar(new Foo("foo"));
            final Bar bar2 = new Bar(null);
            final Bar[] bars = new Bar[]{
                    null,
                    bar1,
                    bar2,
            };
            final List<String> strings = Arrays
                    .stream(bars)
                    .map(Bar::getFoo)
                    .filter(Objects::nonNull)
                    .map(Foo::getString)
                    .collect(Collectors.toList());
            System.out.println("strings: " + strings);
    
        }
    }
    

    同样的问题也发生在 .map(Foo::getString) 打电话。讽刺的是,Android Studio没有抱怨我的 .map(Bar::getFoo) 打电话尽管那肯定是扔了一个 空指针异常 .

    1 回复  |  直到 6 年前
        1
  •  1
  •   weston    6 年前

    这是一个安卓工作室的bug,因为这里没有任何安卓工作室的建议。

    没有警告:

    No Warning

    应用建议并获得警告:

    Warning

    它还建议插入 .filter(Objects::nonNull) 当它已经存在的时候就开始。

    Insert step

    所以它确实是一个臭虫。

    这是真的 此问题的CVE:

    import android.support.annotation.Nullable; // or any nullable you care to use
    
    import java.util.Arrays;
    import java.util.Objects;
    
    public class MCVE {
    
        class Foo {
        }
    
        class Bar {
            @Nullable
            private final Foo foo;
    
            Bar(@Nullable Foo foo) {
                this.foo = foo;
            }
    
            @Nullable
            Foo getFoo() {
                return foo;
            }
        }
    
        public void mcve() {
            final Bar[] bars = new Bar[]{
                    new Bar(new Foo()),
            };
            Arrays.stream(bars)
                    .map(Bar::getFoo)
                    .filter(Objects::nonNull)
                    .map(Foo::toString);
        }
    }
    
    推荐文章