I'm using annotations to ensure that parameter will be not null, assuming this would cause compiler check.
public @Nullable ApplicationAccount accountForKey(@NonNull String key) {
return accounts.get(key);
}
However, by running this code I get NullPointerException exactly on this line
java.util.concurrent.ConcurrentHashMap.get (ConcurrentHashMap.java:883)
What is the point of annotations then?
Even more obscuring, if I write additional check like this
return key!=null?accounts.get(key):null;
Android Studio warns me that the check is useless!
Update: full call stack:
Caused by java.lang.NullPointerException
at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:883)
at co.getcontrol.services.MerchantCenter.accountForKey(MerchantCenter.java:72)
at co.getcontrol.model.customers.CustomersAggregator.loadCustomerDetails(CustomersAggregator.java:91)
at co.getcontrol.model.customers.CustomerDetailsPresenter.callData(CustomerDetailsPresenter.java:39)
at co.getcontrol.reskin.ui.customers.CustomerDetailsViewFragment.onCreateView(CustomerDetailsViewFragment.java:152)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1974)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1252)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1617)
at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:339)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:602)
at co.getcontrol.ui.ControlActivity.onStart(ControlActivity.java:13)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1174)
at android.app.Activity.performStart(Activity.java:5353)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2352)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2441)
at android.app.ActivityThread.access$900(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1354)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5345)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:828)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:644)
at dalvik.system.NativeStart.main(NativeStart.java)
Annotations create a contract. @NonNull
says that this method does not accept null
and passing it may crash the program (which is exactly what happened). Android Studio will warn about any uses of this method where it can deduce that null
may be passed. But it won't prevent passing a null
.
Very similar contract is parameter to []
for an array which cannot be outside of its bounds (e.g. smaller than 0) but that still won't prevent a developer to pass a value outside of the bounds.
The check for null
is marked as superfluous because by the contract, there should never be null
. If you add the check, the method will now know how to handle null
and therefore should not be marked as @NonNull
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With