Java Map.get und Map.containsKey
Bei Verwendung der Java-Map-Implementierungen ist es manchmal üblich, die Map
Methode get (Object) aufzurufen und unterschiedlich zu reagieren, je nachdem, ob der zurückgegebene Wert null ist oder nicht. Es kann allgemein angenommen werden, dass eine von Map.get (Object) zurückgegebene Null angibt, dass der angegebene Schlüssel in der Karte keinen Eintrag enthält. Dies ist jedoch nicht immer der Fall. Wenn eine Java- Map
Implementierung Nullwerte zulässt, kann der Map
Wert zwar für den angegebenen Schlüssel zurückgegeben werden, dieser Wert kann jedoch Null sein. Oft spielt dies keine Rolle, aber wenn dies der Fall ist, kann mit Map.containsKey () festgestellt werden, ob der Map
Eintrag einen Schlüsseleintrag enthält. Wenn dies der Fall ist und die Map
Rückgabe null
bei einem get-Aufruf für denselben Schlüssel erfolgt, ist es wahrscheinlich, dass der Schlüssel einem zugeordnet istnull
Wert. Mit anderen Worten, das Map
könnte "true" für zurückgeben, containsKey(Object)
während gleichzeitig " null
" für "zurückgegeben wird get(Object)
. Es gibt einige Map
Implementierungen, die keine null
Werte zulassen . In diesen Fällen sollte ein null
Aufruf von "get" konsistent mit einer Rückgabe von "false" von der Methode "includesKey" übereinstimmen.
In diesem Blogbeitrag zeige ich diese Aspekte von Map.get(Object)
und Map.containsKey(Object)
. Bevor ich auf diese Demonstration eingehe, möchte ich zunächst darauf hinweisen, dass die Javadoc-Dokumentation für Map.get (Object) ausdrücklich vor den subtilen Unterschieden zwischen Map.get(Object)
und warnt Map.containsKey(Object)
:
null
nicht unbedingt, dass die Zuordnung keine Zuordnung für den Schlüssel enthält. Es ist auch möglich, dass die Karte den Schlüssel explizit zuordnet
null
. Die
containsKey
Operation kann verwendet werden, um diese beiden Fälle zu unterscheiden.
Für die Beispiele des Beitrags werde ich die als nächstes definierte Staatenaufzählung verwenden:
States.java
package dustin.examples; /** * Enum representing select western states in the United Sates. */ public enum States { ARIZONA("Arizona"), CALIFORNIA("California"), COLORADO("Colorado"), IDAHO("Idaho"), KANSAS("Kansas"), MONTANA("Montana"), NEVADA("Nevada"), NEW_MEXICO("New Mexico"), NORTH_DAKOTA("North Dakota"), OREGON("Oregon"), SOUTH_DAKOTA("South Dakota"), UTAH("Utah"), WASHINGTON("Washington"), WYOMING("Wyoming"); /** State name. */ private String stateName; /** * Parameterized enum constructor accepting a state name. * * @param newStateName Name of the state. */ States(final String newStateName) { this.stateName = newStateName; } /** * Provide the name of the state. * * @return Name of the state */ public String getStateName() { return this.stateName; } }
Die nächste Codeauflistung verwendet die obige Aufzählung und füllt eine Karte der Bundesstaaten mit ihren Hauptstädten. Die Methode akzeptiert eine Klasse, die die spezifische Implementierung von Map sein soll, die generiert und gefüllt werden soll.
generateStatesMap (Klasse)
/** * Generate and populate a Map of states to capitals with provided Map type. * This method also logs any Map implementations for which null values are * not allowed. * * @param mapClass Type of Map to be generated. * @return Map of states to capitals. */ private static Map generateStatesMap(Class mapClass) { Map mapToPopulate = null; if (Map.class.isAssignableFrom(mapClass)) { try { mapToPopulate = mapClass != EnumMap.class ? (Map) mapClass.newInstance() : getEnumMap(); mapToPopulate.put(States.ARIZONA, "Phoenix"); mapToPopulate.put(States.CALIFORNIA, "Sacramento"); mapToPopulate.put(States.COLORADO, "Denver"); mapToPopulate.put(States.IDAHO, "Boise"); mapToPopulate.put(States.NEVADA, "Carson City"); mapToPopulate.put(States.NEW_MEXICO, "Sante Fe"); mapToPopulate.put(States.NORTH_DAKOTA, "Bismark"); mapToPopulate.put(States.OREGON, "Salem"); mapToPopulate.put(States.SOUTH_DAKOTA, "Pierre"); mapToPopulate.put(States.UTAH, "Salt Lake City"); mapToPopulate.put(States.WASHINGTON, "Olympia"); mapToPopulate.put(States.WYOMING, "Cheyenne"); try { mapToPopulate.put(States.MONTANA, null); } catch (NullPointerException npe) { LOGGER.severe( mapToPopulate.getClass().getCanonicalName() + " does not allow for null values - " + npe.toString()); } } catch (InstantiationException instantiationException) { LOGGER.log( Level.SEVERE, "Unable to instantiate Map of type " + mapClass.getName() + instantiationException.toString(), instantiationException); } catch (IllegalAccessException illegalAccessException) { LOGGER.log( Level.SEVERE, "Unable to access Map of type " + mapClass.getName() + illegalAccessException.toString(), illegalAccessException); } } else { LOGGER.warning("Provided data type " + mapClass.getName() + " is not a Map."); } return mapToPopulate; }
Die obige Methode kann verwendet werden, um Karten verschiedener Art zu generieren. Der Code wird derzeit nicht angezeigt, aber in meinem Beispiel werden diese Maps mit vier spezifischen Implementierungen erstellt: HashMap, LinkedHashMap, ConcurrentHashMap und EnumMap. Jede dieser vier Implementierungen wird dann durch die Methode ausgeführt demonstrateGetAndContains(Map)
, die als nächstes gezeigt wird.
demonstrGetAndContains (Karte)
/** * Demonstrate Map.get(States) and Map.containsKey(States). * * @param map Map upon which demonstration should be conducted. */ private static void demonstrateGetAndContains(final Map map) { final StringBuilder demoResults = new StringBuilder(); final String mapType = map.getClass().getCanonicalName(); final States montana = States.MONTANA; demoResults.append(NEW_LINE); demoResults.append( "Map of type " + mapType + " returns " + (map.get(montana)) + " for Map.get() using " + montana.getStateName()); demoResults.append(NEW_LINE); demoResults.append( "Map of type " + mapType + " returns " + (map.containsKey(montana)) + " for Map.containsKey() using " + montana.getStateName()); demoResults.append(NEW_LINE); final States kansas = States.KANSAS; demoResults.append( "Map of type " + mapType + " returns " + (map.get(kansas)) + " for Map.get() using " + kansas.getStateName()); demoResults.append(NEW_LINE); demoResults.append( "Map of type " + mapType + " returns " + (map.containsKey(kansas)) + " for Map.containsKey() using " + kansas.getStateName()); demoResults.append(NEW_LINE); LOGGER.info(demoResults.toString()); }
Für diese Demonstration habe ich die Karten absichtlich so eingerichtet, dass sie für Montana Nullkapitalwerte haben, für Kansas überhaupt keinen Eintrag. Dies hilft, die Unterschiede in Map.get(Object)
und zu demonstrieren Map.containsKey(Object)
. Da nicht jeder Map-Implementierungstyp Nullwerte zulässt, habe ich den Teil, der Montana ohne Großbuchstaben enthält, in einen Try / Catch-Block eingefügt.
Die Ergebnisse der Ausführung der vier Kartentypen durch den Code werden als Nächstes angezeigt.
Aug 17, 2010 11:23:26 PM dustin.examples.MapContainsGet logMapInfo INFO: HashMap: {MONTANA=null, WASHINGTON=Olympia, ARIZONA=Phoenix, CALIFORNIA=Sacramento, WYOMING=Cheyenne, SOUTH_DAKOTA=Pierre, COLORADO=Denver, NEW_MEXICO=Sante Fe, NORTH_DAKOTA=Bismark, NEVADA=Carson City, OREGON=Salem, UTAH=Salt Lake City, IDAHO=Boise} Aug 17, 2010 11:23:26 PM dustin.examples.MapContainsGet demonstrateGetAndContains INFO: Map of type java.util.HashMap returns null for Map.get() using Montana Map of type java.util.HashMap returns true for Map.containsKey() using Montana Map of type java.util.HashMap returns null for Map.get() using Kansas Map of type java.util.HashMap returns false for Map.containsKey() using Kansas Aug 17, 2010 11:23:26 PM dustin.examples.MapContainsGet logMapInfo INFO: LinkedHashMap: {ARIZONA=Phoenix, CALIFORNIA=Sacramento, COLORADO=Denver, IDAHO=Boise, NEVADA=Carson City, NEW_MEXICO=Sante Fe, NORTH_DAKOTA=Bismark, OREGON=Salem, SOUTH_DAKOTA=Pierre, UTAH=Salt Lake City, WASHINGTON=Olympia, WYOMING=Cheyenne, MONTANA=null} Aug 17, 2010 11:23:26 PM dustin.examples.MapContainsGet demonstrateGetAndContains INFO: Map of type java.util.LinkedHashMap returns null for Map.get() using Montana Map of type java.util.LinkedHashMap returns true for Map.containsKey() using Montana Map of type java.util.LinkedHashMap returns null for Map.get() using Kansas Map of type java.util.LinkedHashMap returns false for Map.containsKey() using Kansas Aug 17, 2010 11:23:26 PM dustin.examples.MapContainsGet generateStatesMap SEVERE: java.util.concurrent.ConcurrentHashMap does not allow for null values - java.lang.NullPointerException Aug 17, 2010 11:23:26 PM dustin.examples.MapContainsGet logMapInfo INFO: ConcurrentHashMap: {SOUTH_DAKOTA=Pierre, ARIZONA=Phoenix, WYOMING=Cheyenne, UTAH=Salt Lake City, OREGON=Salem, CALIFORNIA=Sacramento, IDAHO=Boise, NEW_MEXICO=Sante Fe, COLORADO=Denver, NORTH_DAKOTA=Bismark, WASHINGTON=Olympia, NEVADA=Carson City} Aug 17, 2010 11:23:26 PM dustin.examples.MapContainsGet demonstrateGetAndContains INFO: Map of type java.util.concurrent.ConcurrentHashMap returns null for Map.get() using Montana Map of type java.util.concurrent.ConcurrentHashMap returns false for Map.containsKey() using Montana Map of type java.util.concurrent.ConcurrentHashMap returns null for Map.get() using Kansas Map of type java.util.concurrent.ConcurrentHashMap returns false for Map.containsKey() using Kansas Aug 17, 2010 11:23:26 PM dustin.examples.MapContainsGet logMapInfo INFO: EnumMap: {ARIZONA=Phoenix, CALIFORNIA=Sacramento, COLORADO=Denver, IDAHO=Boise, MONTANA=null, NEVADA=Carson City, NEW_MEXICO=Sante Fe, NORTH_DAKOTA=Bismark, OREGON=Salem, SOUTH_DAKOTA=Pierre, UTAH=Salt Lake City, WASHINGTON=Olympia, WYOMING=Cheyenne} Aug 17, 2010 11:23:26 PM dustin.examples.MapContainsGet demonstrateGetAndContains INFO: Map of type java.util.EnumMap returns null for Map.get() using Montana Map of type java.util.EnumMap returns true for Map.containsKey() using Montana Map of type java.util.EnumMap returns null for Map.get() using Kansas Map of type java.util.EnumMap returns false for Map.containsKey() using Kansas
Für die drei Map-Typen, für die ich Nullwerte eingeben konnte, gibt der Map.get (Object) -Aufruf null zurück, auch wenn die includesKey (Object) -Methode für Montana "true" zurückgibt, da ich diesen Schlüssel ohne a in die Map eingefügt habe Wert. Für Kansas sind die Ergebnisse konsistent Map.get () gibt null zurück und Map.containsKey () gibt "false" zurück, da in den Karten für Kansas überhaupt kein Eintrag vorhanden ist.
Die obige Ausgabe zeigt auch, dass ich keinen Nullwert für Montanas Kapital in die ConcurrentHashMap
Implementierung einfügen konnte (eine NullPointerException wurde ausgelöst).
17. August 2010, 23:23:26 Uhr Dustin.examples.MapContainsGet generateStatesMapSEVERE: java.util.concurrent.ConcurrentHashMap lässt keine Nullwerte zu - java.lang.NullPointerException
Dies hatte den Nebeneffekt der Haltung Map.get(Object)
und Map.containsKey(Object)
eine einheitlichere jeweiligen null und falsche Rückgabewerte. Mit anderen Worten, es war unmöglich, einen Schlüssel in der Karte zu haben, ohne einen entsprechenden Wert ungleich Null zu haben.
In vielen Fällen wird die Map.get(Object)
Arbeit nach Bedarf für die jeweiligen Bedürfnisse verwendet. Beachten Sie jedoch am besten, dass es Unterschiede gibt, Map.get(Object)
und Map.containsKey(Object)
stellen Sie sicher, dass immer die entsprechende verwendet wird. Es ist auch interessant festzustellen, dass Map auch eine ähnliche containsValue(Object)
Methode bietet .
Der Vollständigkeit halber liste ich hier die gesamte Codeliste für die MapContainsGet-Klasse auf:
MapContainsGet.java