Programmering

Java Map.get og Map.containsKey

Når du bruker Java's Map-implementeringer, er det noen ganger vanlig å påkalle Kart's get (Object) metode og å reagere forskjellig basert på om verdien som returneres er null eller ikke. Det kan antas at en null som returneres fra Map.get (Object) indikerer at det ikke er noen oppføring med den oppgitte nøkkelen på kartet, men dette er ikke alltid tilfelle. Faktisk, hvis en Java Kart implementering tillater nullverdier, så er det mulig for Kart for å returnere verdien for den gitte nøkkelen, men den verdien kan være null. Ofte betyr ikke dette noe, men hvis det gjør det, kan man bruke Map.containsKey () for å avgjøre om Kart oppføringen har en nøkkeloppføring. Hvis det gjør det og Kart returnerer null på et ringeanrop for den samme nøkkelen, er det sannsynlig at nøkkelen tilordnes til null verdi. Med andre ord det Kart kan returnere "sant" for inneholderKey (Objekt) samtidig som vi kommer tilbake " null"for få (Objekt). Det er noen Kart implementeringer som ikke tillater det null verdier. I disse tilfellene, a null fra et "få" -anrop bør konsekvent matche en "falsk" retur fra "inneholderKey" -metoden.

I dette blogginnlegget demonstrerer jeg disse aspektene av Map.get (Objekt) og Map.containsKey (Object). Før jeg går inn i demonstrasjonen, vil jeg først påpeke at Javadoc-dokumentasjonen for Map.get (Object) eksplisitt advarer om de subtile forskjellene mellom Map.get (Objekt) og Map.containsKey (Object):

Hvis dette kartet tillater nullverdier, så er returverdien på null indikerer ikke nødvendigvis at kartet ikke inneholder noen kartlegging for nøkkelen; det er også mulig at kartet eksplisitt tilordner nøkkelen til null. De inneholder nøkkel operasjonen kan brukes til å skille mellom disse to tilfellene.

For innleggets eksempler vil jeg bruke States enum definert neste:

States.java

pakke dustin. eksempler; / ** * Enum som representerer utvalgte vestlige stater i USA. * / 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"); / ** Oppgi navn. * / private String stateName; / ** * Parameterisert enumkonstruktør som aksepterer et tilstandsnavn. * * @param newStateName Navnet på staten. * / States (final String newStateName) {this.stateName = newStateName; } / ** * Oppgi navnet på staten. * * @return Navn på staten * / public String getStateName () {returner this.stateName; }} 

Den neste kodelisten bruker enumet ovenfor og fyller ut et kart over stater til hovedstaden. Metoden godtar en klasse som skal være den spesifikke implementeringen av Map som skal genereres og fylles ut.

createStatesMap (Class)

/ ** * Generer og fyll ut et kart over stater til hovedsteder med gitt karttype. * Denne metoden logger også alle kartimplementeringer som nullverdier er * ikke tillatt for. * * @param mapClass Type kart som skal genereres. * @ retur Kart over stater til hovedsteder. * / privat statisk kart generereStatesMap (Class mapClass) {Map mapToPopulate = null; hvis (Map.class.isAssignableFrom (mapClass)) {prøv {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 (stater.UTAH, "Salt Lake City"); mapToPopulate.put (States.WASHINGTON, "Olympia"); mapToPopulate.put (States.WYOMING, "Cheyenne"); prøv {mapToPopulate.put (States.MONTANA, null); } catch (NullPointerException npe) {LOGGER.severe (mapToPopulate.getClass (). getCanonicalName () + "tillater ikke nullverdier -" + npe.toString ()); }} fangst (InstantiationException instantiationException) {LOGGER.log (Level.SEVERE, "Unable to instantiate Map of type" + mapClass.getName () + instantiationException.toString (), instantiationException); } fangst (IllegalAccessException illegalAccessException) {LOGGER.log (Level.SEVERE, "Unable to access Map of type" + mapClass.getName () + illegalAccessException.toString (), illegalAccessException); }} annet {LOGGER.warning ("Forutsatt datatype" + mapClass.getName () + "er ikke et kart."); } returner mapToPopulate; } 

Metoden ovenfor kan brukes til å generere kart av forskjellige slag. Jeg viser ikke koden akkurat nå, men eksemplet mitt lager disse kartene med fire spesifikke implementeringer: HashMap, LinkedHashMap, ConcurrentHashMap og EnumMap. Hver av disse fire implementeringene kjøres deretter gjennom metoden demonstrGetAndContains (Map), som vises neste.

demonstrGetAndContains (Map)

/ ** * Demonstrer Map.get (States) og Map.containsKey (States). * * @param kart Kart som demonstrasjonen skal gjennomføres på. * / private static void demonstrGetAndContains (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 ("Kart av type" + mapType + "returnerer" + (map.get (montana)) + "for Map.get () ved hjelp av" + montana.getStateName ()); demoResults.append (NEW_LINE); demoResults.append ("Kart av type" + mapType + "returnerer" + (map.containsKey (montana)) + "for Map.containsKey () ved hjelp av" + montana.getStateName ()); demoResults.append (NEW_LINE); final States kansas = States.KANSAS; demoResults.append ("Kart av type" + mapType + "returnerer" + (map.get (kansas)) + "for Map.get () ved hjelp av" + kansas.getStateName ()); demoResults.append (NEW_LINE); demoResults.append ("Kart av type" + mapType + "returnerer" + (map.containsKey (kansas)) + "for Map.containsKey () ved hjelp av" + kansas.getStateName ()); demoResults.append (NEW_LINE); LOGGER.info (demoResults.toString ()); } 

For denne demonstrasjonen satte jeg med vilje opp Kartene for å ha nullverdier for Montana for ikke å ha noen oppføring i det hele tatt for Kansas. Dette er med på å demonstrere forskjellene i Map.get (Objekt) og Map.containsKey (Object). Fordi ikke alle Map-implementeringstyper tillater nullverdier, omringet jeg den delen som setter Montana uten hovedstad i en prøve / fangst-blokk.

Resultatene av å kjøre de fire typene Kart gjennom koden vises neste.

17. august 2010, 11:23:26 dustin.examples.MapContainsGet logMapInfo INFO: HashMap: {MONTANA = null, WASHINGTON = Olympia, ARIZONA = Phoenix, CALIFORNIA = Sacramento, WYOMING = Cheyenne, SOUTH_DAKOTA = Pierre, COLORADOIC = Denver = Sante Fe, NORTH_DAKOTA = Bismark, NEVADA = Carson City, OREGON = Salem, UTAH = Salt Lake City, IDAHO = Boise} 17. august 2010 23:23:26 dustin.examples.MapContainsGet demonstrGetAndContains INFO: Kart over typen java. util.HashMap returnerer null for Map.get () ved hjelp av Montana Kart av typen java.util.HashMap returnerer true for Map.containsKey () ved hjelp av Montana Kart av typen java.util.HashMap returnerer null for Map.get () ved bruk av Kansas Map av typen java.util.HashMap returnerer false for Map.containsKey () ved bruk av Kansas 17. august 2010, 23:23:26 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} 17. august 2010 23:23:26 dustin.examples.MapContainsGet demonstrGetAndContains INFO: Kart av typen java.util.LinkedHashMap returnerer null for Map.get () ved hjelp av Montana Map av typen java .util.LinkedHashMap returnerer true for Map.containsKey () ved hjelp av Montana Map av typen java.util.LinkedHashMap returnerer null for Map.get () ved bruk av Kansas Kart av typen java.util.LinkedHashMap returnerer false for Map.containsKey () ved bruk av Kansas 17. august 2010, 23:23:26 dustin.examples.MapContainsGet generereStatesMap SEVERE: java.util.concurrent.ConcurrentHashMap tillater ikke nullverdier - java.lang.NullPointerException 17. august 2010 23:23:26 dustin.examples .MapContainsGet logMapInfo INFO: ConcurrentHashMap: {SOUTH_DAKOTA = Pierre, ARIZONA = Phoenix, WYOMING = Cheyenne, UTAH = Salt Lake City, OREGON = Salem, CALIFORNIA = Sacramento, IDAHO = Boise, NEW_MEXICOO = Sante Fe, Sante Fe, Sante Fe, SAD , WASHINGTON = Olympia, NEVADA = Carson City} 17. august 2010 23:23:26 dustin.examples.Ma pContainsGet demonstrGetAndContains INFO: Kart av typen java.util.concurrent.ConcurrentHashMap returnerer null for Map.get () ved hjelp av Montana Kart av typen java.util.concurrent.ConcurrentHashMap returnerer false for Map.containsKey () ved hjelp av Montana Map av typen java.util .concurrent.ConcurrentHashMap returnerer null for Map.get () ved hjelp av Kansas Map av typen java.util.concurrent.ConcurrentHashMap returnerer false for Map.containsKey () ved bruk av Kansas 17. august 2010 23:23:26 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 Lake City, WASHINGTON = Olympia, WYOMING = Cheyenne} 17. august 2010, 23:23:26 dustin.examples.MapContainsGet demonstrGetAndContains INFO: Kart av typen java.util.EnumMap returnerer null for Map.get () ved hjelp av Montana Map of type java.util.EnumMap returnerer true for Map.containsKey () ved hjelp av Montana Map of ty pe java.util.EnumMap returnerer null for Map.get () ved bruk av Kansas Kart av typen java.util.EnumMap returnerer false for Map.containsKey () ved bruk av Kansas 

For de tre karttypene som jeg kunne legge inn nullverdier for, returnerer Map.get (Object) -anropet null selv når den inneholderKey (Object) -metoden returnerer "true" for Montana fordi jeg la den nøkkelen på kartet uten verdi. For Kansas er resultatene konsekvent Map.get () returnerer null og Map.containsKey () returnerer "false" fordi det ikke er noen oppføring i Maps for Kansas.

Resultatet ovenfor viser også at jeg ikke kunne sette en nullverdi for Montanas hovedstad i ConcurrentHashMap implementering (et NullPointerException ble kastet).

17. august 2010, 23:23:26 dustin.examples.MapContainsGet createStatesMapSEVERE: java.util.concurrent.ConcurrentHashMap tillater ikke nullverdier - java.lang.NullPointerException

Dette hadde bieffekten av å holde Map.get (Objekt) og Map.containsKey (Object) en mer konsistent respektiv null og falsk returverdi. Det var med andre ord umulig å ha en nøkkel i kartet uten å ha en tilsvarende ikke-null verdi.

I mange tilfeller, bruk av Map.get (Objekt) fungerer etter behov for de spesielle behovene, men det er best å huske at det er forskjeller mellom Map.get (Objekt) og Map.containsKey (Object) for å sikre at den riktige alltid brukes. Det er også interessant å merke seg at Map har et lignende containsValue (Object) metode også.

Jeg lister opp hele kodelisten for MapContainsGet-klassen her for fullstendighet:

MapContainsGet.java