I have a function which returns an int
value for a given key (from a HashMap<String, Integer>
). If the key doesn't exist, I want to return something the caller can check for. It seems that, most commonly, this would be a "returns -1 if key doesn't exist" kind of thing. However, I can't reserve -1 for that purpose in my case, because negative numbers are feasible values for keys which do exist.
The only other o开发者_开发技巧ptions I have been able to come up with are the following:
- Change return type to
Integer
wrapper class and check fornull
- Return something very unlikely, such as
Integer.MIN_VALUE
- Make an additional
boolean keyExists(String key)
function which should always be called first - Switch to
float
and useNaN
instead
I am writing this in Java, but people from similar language backgrounds are welcome to post. Thanks!
The first option is, in my opinion, the cleanest. Magic numbers like -1 and Integer.MIN_VALUE are kind of messy, especially when the values aren't intuitive. That is an idiomatic C solution, which Java developers will hate you for. Depending on what you're actually using this for you could also throw a "KeyNotFoundException" if this only happens in "exceptional" circumstances.
I vote for throwing a checked exception here. Generally I dislike checked exceptions but it seems like a reasonable thing to do in this case. The case where the value is not present will need to be handled separately from the case where the value is present, using an exception would make that clear.
Actually your idea to add a keyExists method is the best of the ideas you list, because it doesn't rely on the user knowing to look for a special value. If you go that way then you could throw an exception as a backup plan in case the map contents change between the call to keyExists and the retrieval.
Although it depends heavily on the application and know constraints, I would prefer #1 above. The reason is because then it is explicit - it is always better to have an explicit situation than an implicit - such as MIN_VALUE - in my experience.
Another option is to have a wrapper object that contains the result value as a primitive int, but also has a status value or something similar. So it could be something like:
public class Wrapper {
private int value = Integer.MIN_VALUE;
private boolean isValid;
// appropriate getters and setters etc.
}
You could also include an enum instead of a boolean to have a state instead, depending on the complexity of the problem. If you see this element holding composite information - sets of information keyed of single keys, or something similar - a container object or status object can be very valuable in those cases.
float is unsafe as not all int values can be accurate represented as int values. long is a better options as all int values can be safely stored as long and you will have plenty more values for not-found.
If you are using a Map you have an Integer object anyway so why not return that (or null)
If you really want to use primitives (for efficiency ??) I suggest you look at TObjectIntHashMap instead. This uses primitive int values. To check for absense, you have to check containsKey() seperately.
Two situations are typical:
- You have a high expectation of finding a value for a particular key.
- You are not sure if a particular key has a value stored.
If assumption 1 is wrong, then it's likely to indicate a bug, so protect your assumption in the access method with an assertion.
If 2 applies, how would you be sure about what's returned? so provide a test method such as "keyExists" and know absolutely before accessing the map.
In case 1, no checking is required, which is much cleaner, but the access will fail if you are wrong. With special cases such as -1 or Integer.MIN_VALUE it is very hard to be sure that they won't be used.
Languages like Haskell, Scala and C# have special types to convey presence / absence of a value which is far better than use of null (if you forget to test you will likely get a NullPointerException)
Option 5: Throw an Exception
Although, in this case, I'd vote for using the Integer class.
I think you should combine options #1 and #3, since that's consistent with the behavior of the underlying HashMap. From HashMap's get method documentation:
Returns the value to which the specified key is mapped in this identity hash map, or null if the map contains no mapping for this key. A return value of null does not necessarily indicate that the map contains no mapping for the key; it is also possible that the map explicitly maps the key to null. The containsKey method may be used to distinguish these two cases.
- Change return type to Integer wrapper class and check for null.
This is the more common option.
精彩评论