1

I've updated Android Studio to the latest version, 1.2. I've also recently updated other components like the Android Gradle Extensions.

Now I'm getting warned on methods that I had previously annotated as NotNull. The warning is: Expression might evaluate to null but is returned by the method declared as @NotNull

Here's an example:

public class MyApplication extends Application {
    private static SharedPreferences sPrefs = null;

    /**
     * Corresponds to a string value.
     *
     * @see #setDeviceInfo(String, String, String)
     */
    private static final String PREF_DEVICE_INFO_DEVICE_ADDRESS = "deviceaddress";

    @Override
    public void onCreate() {
        super.onCreate();
        sPrefs = PreferenceManager.getDefaultSharedPreferences(this);
    }

    @NonNull
    public static String getDeviceAddress() {
        return sPrefs.getString(PREF_DEVICE_INFO_DEVICE_ADDRESS, "");
    }
}

I would think that there is no way for getString to return null in this case because I have have set a default value, ""

And even when I look at the implementation of getString (in API 22 anyway) it would seem that this is a case where android studio has simply ignored the fact that my default value is not null and made a false assumption that the default value could be null.
API 22 implementation:

public String getString(String key, String defValue) {
    synchronized (this) {
        awaitLoadedLocked();
        String v = (String)mMap.get(key);
        return v != null ? v : defValue;
    }
}

Still I need the community to put me at ease or point out what I'm missing before I move on.

Jon
  • 9,156
  • 9
  • 56
  • 73

1 Answers1

2

You are Safe

You are indeed safe.

You're specifying a default value, and the method cannot return a null value (except if you specify it as your defValue).

Why the Warning Then??

For a number of reasons, IntelliJ/AndroidStudio was just unable to determine the escape route and to figure out your method usage was safe. And the method contracts doesn't formally reject null values for the defValue.

Also, you annotate your method as @NotNull but getString itself isn't annotated (and these are not necessarily runtime checks).

Finally, I wonder if you didn't mistakenly switch your annotations between @NotNull and @NonNull, and consequently switched the implementation provider for your annotation checking. You mention @NotNull in your error and your description, but the code uses @NonNull. They don't behave identically. IntelliJ's NonNull, for instance, is a static-only check.

See Which @NotNull Java annotation should I use? for a nice summary.

Other Possible Issues

Bringing these up just in case...

Possible NPE on getString for a null key

However, if you specify a null key, you could get a NullPointerException thrown by the Map. But that depends on the map implementation used and if that map doesn't allow null keys (I haven't looked into it), and that's not an issue for you (at least not in the code snippet you provided).

As SharedPreferences doesn't specify in its contract anything about the implementation, should just trust what the JDK's Map.get() documentation states:

NullPointerException - if the specified key is null and this map does not permit null keys (optional)

Possible ClassCastException

Beware as well that the SharedPreferences.getString documentation warns you could get a ClassCastException if the stored preference isn't of type String (I suppose unlikely in your case, but I'm mentioning it just in case):

Throws ClassCastException if there is a preference with this name that is not a String.

Community
  • 1
  • 1
haylem
  • 22,460
  • 3
  • 67
  • 96
  • I certainly use only `@NonNull` and `@Nullable` annotations from the android support annotation namespace. But the warning does indeed mention `@NotNull`. My guess is it is a side effect of some rule generalization and isn't significant. Thanks for the thorough answer! – Jon May 21 '15 at 20:10
  • @Jonathan727: you're welcome. I'm rarely on SO lately and I saw your question just before leaving the office, so I thought I'd take a stab at it. Wish I'd have more time to get deeper but it's trickier these days :) Glad it helped. – haylem May 22 '15 at 13:59