Reputation: 2089
I have a method that gets something from a hashmap, a simplified example (that doesn't make much sense but is good enough for now) is:
private Map<String,String> map = new HashMap<String,String>();
public String get(String key) {
return map.get(key);
}
This method can return a null when an entry doesn't exist for a given key obviously. The thing is, I want to annotate this method with @NonNull
(because it is used in a gazillion places and I don't like Intellij spamming me with inspection warnings about producing a NPE and I don't want to turn off that inspection, and I also don't want to check whether the value returned is different than null everywhere I call this method. This is because I always use this method with a bunch of keys that are ALWAYS in the map. So due to the program logic this method is bound to return a @NonNull
value.
I am tempted to just annotate it with a @NonNull
, but who knows someone may call it with something other than the defined keys somewhere and actually cause a NullPointerException.
What would you do? An assertion sounds tempting to me.. Or would you just change the method to throw a RuntimException ? Or an AssertionError?
Thanks.
Edit:
here's the actual implementation:
/**
* Typesafe heterogeneous container pattern - implementation
*/
public class HandlersMap {
private final Map<Class<? extends TableHandler>, TableHandler> handlers;
public HandlersMap() {
handlers = new HashMap<Class<? extends TableHandler>, TableHandler>();
putHandler(RolesTableHandler.class, new RolesTableHandler());
putHandler(UsersTableHandler.class, new UsersTableHandler());
putHandler(DevicesTableHandler.class, new DevicesTableHandler());
}
private <T extends TableHandler> void putHandler(@NonNull final Class<T> type, @NonNull final T instance) {
handlers.put(type, type.cast(instance));
}
@NonNull
public <T extends TableHandler> T getHandler(@NonNull final Class<T> type) {
assert handlers.get(type) != null;
return type.cast(handlers.get(type));
}
public Collection<TableHandler> values() {
return handlers.values();
}
public int size() {
return handlers.size();
}
public Map<Class<? extends TableHandler>, TableHandler> getMap() {
return this.handlers;
}
}
Upvotes: 3
Views: 9099
Reputation: 1931
Annotating with @Nonnull
without verifying if the given key exists is definitely the wrong thing to do.
Since you seem to indicate that the given key is expected to exist, this means a missing key is an invalid argument, so checking for this case and throwing an IllegalArgumentException
for missing elements would be the proper thing to do.
Alternatively, depending on how your map is initialized, you might want to consider creating an enum for your key values, use an EnumMap
instead of a HashMap
, and have your get()
method take this enum rather than a free-form String
. That way, you would have some compile-time checking to ensure proper values are used as well.
Even in that case though, you'd still need to check for existence, just in case the requested enum value is not yet added to the map.
Upvotes: 7