Programmering

Java Map.get og Map.containsKey

Når du bruger Java's Map-implementeringer, er det undertiden almindeligt at påberåbe sig Kort's get (Object) metode og reagere forskelligt baseret på om den returnerede værdi er nul eller ej. En almindelig antagelse kan antages, at en nul returneret fra Map.get (Object) angiver, at der ikke er nogen post med den angivne nøgle på kortet, men dette er ikke altid tilfældet. Faktisk, hvis en Java Kort implementering giver mulighed for nulværdier, så er det muligt for Kort for at returnere sin værdi for den givne nøgle, men den værdi kan være nul. Ofte betyder det ikke noget, men hvis det gør det, kan man bruge Map.containsKey () til at afgøre, om Kort indtastning har en nøgleindgang. Hvis det gør det og Kort vender tilbage nul på et get-opkald til den samme nøgle, så er det sandsynligt, at nøglen kortlægges til en nul værdi. Med andre ord det Kort returnerer muligvis "sand" for indeholderKey (objekt) samtidig med at vende tilbage " nul" til få (Objekt). Der er nogle Kort implementeringer, der ikke tillader det nul værdier. I disse tilfælde er a nul fra et "get" -opkald skal konsekvent matche et "false" return fra "containKey" -metoden.

I dette blogindlæg demonstrerer jeg disse aspekter af Map.get (Objekt) og Map.containsKey (Objekt). Før jeg går ind i denne demonstration, vil jeg først påpege, at Javadoc-dokumentationen til Map.get (Object) eksplicit advarer om de subtile forskelle mellem Map.get (Objekt) og Map.containsKey (Objekt):

Hvis dette kort tillader nulværdier, så er en returværdi på nul indikerer ikke nødvendigvis, at kortet ikke indeholder nogen kortlægning for nøglen; det er også muligt, at kortet eksplicit kortlægger nøglen til nul. Det indeholderKey operation kan bruges til at skelne mellem disse to tilfælde.

For postens eksempler vil jeg bruge det stater, der er defineret derefter:

States.java

pakke dustin. eksempler; / ** * Enum, der repræsenterer udvalgte vestlige stater i De Forenede Stater. * / offentlige enum-stater {ARIZONA ("Arizona"), CALIFORNIA ("Californien"), 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"); / ** Angiv navn. * / private String stateName; / ** * Parametreret enumkonstruktør, der accepterer et tilstandsnavn. * * @param newStateName Statens navn. * / States (final String newStateName) {this.stateName = newStateName; } / ** * Angiv statens navn. * * @return Navn på staten * / public String getStateName () {returner this.stateName; }} 

Den næste kodeliste bruger enummet ovenfor og udfylder et kort over stater til deres hovedstæder. Metoden accepterer en klasse, der skal være den specifikke implementering af Map, der skal genereres og udfyldes.

createStatesMap (klasse)

/ ** * Generer og udfyld et kort over stater til hovedstæder med den angivne korttype. * Denne metode logger også alle kortimplementeringer, for hvilke nullværdier er * ikke tilladt. * * @param mapClass Type kort, der skal genereres. * @return Kort over stater til hovedstæder. * / privat statisk kort 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 (stater.CALIFORNIA, "Sacramento"); mapToPopulate.put (States.COLORADO, "Denver"); mapToPopulate.put (stater.IDAHO, "Boise"); mapToPopulate.put (States.NEVADA, "Carson City"); mapToPopulate.put (States.NEW_MEXICO, "Sante Fe"); mapToPopulate.put (stater.NORTH_DAKOTA, "Bismark"); mapToPopulate.put (States.OREGON, "Salem"); mapToPopulate.put (stater.SOUTH_DAKOTA, "Pierre"); mapToPopulate.put (stater.UTAH, "Salt Lake City"); mapToPopulate.put (stater.WASHINGTON, "Olympia"); mapToPopulate.put (States.WYOMING, "Cheyenne"); prøv {mapToPopulate.put (States.MONTANA, null); } fange (NullPointerException npe) {LOGGER.severe (mapToPopulate.getClass (). getCanonicalName () + "tillader ikke nulværdier -" + npe.toString ()); }} fange (InstantiationException instantiationException) {LOGGER.log (Level.SEVERE, "Unable to instantiate Map of type" + mapClass.getName () + instantiationException.toString (), instantiationException); } fange (IllegalAccessException illegalAccessException) {LOGGER.log (Level.SEVERE, "Kan ikke få adgang til kort af typen" + mapClass.getName () + illegalAccessException.toString (), illegalAccessException); }} andet {LOGGER.warning ("Leveret datatype" + mapClass.getName () + "er ikke et kort."); } returner mapToPopulate; } 

Metoden ovenfor kan bruges til at generere kort af forskellige slags. Jeg viser ikke koden lige nu, men mit eksempel opretter disse kort med fire specifikke implementeringer: HashMap, LinkedHashMap, ConcurrentHashMap og EnumMap. Hver af disse fire implementeringer køres derefter gennem metoden demonstrGetAndContains (kort), som vises næste.

demonstrGetAndContains (kort)

/ ** * Demonstrer Map.get (stater) og Map.containsKey (stater). * * @param kort Kort, hvorpå demonstration skal gennemføres. * / privat statisk ugyldigt demonstrereGetAndContains (endelig kortkort) {final StringBuilder demoResults = new StringBuilder (); endelig String mapType = map.getClass (). getCanonicalName (); endelige stater montana = stater.MONTANA; demoResults.append (NEW_LINE); demoResults.append ("Kort af typen" + mapType + "returnerer" + (map.get (montana)) + "for Map.get () ved hjælp af" + montana.getStateName ()); demoResults.append (NEW_LINE); demoResults.append ("Kort af typen" + mapType + "returnerer" + (map.containsKey (montana)) + "for Map.containsKey () ved hjælp af" + montana.getStateName ()); demoResults.append (NEW_LINE); final States kansas = States.KANSAS; demoResults.append ("Kort af typen" + mapType + "returnerer" + (map.get (kansas)) + "for Map.get () ved hjælp af" + kansas.getStateName ()); demoResults.append (NEW_LINE); demoResults.append ("Kort af typen" + mapType + "returnerer" + (map.containsKey (kansas)) + "for Map.containsKey () ved hjælp af" + kansas.getStateName ()); demoResults.append (NEW_LINE); LOGGER.info (demoResults.toString ()); } 

Til denne demonstration satte jeg bevidst kortene op til at have nul kapitalværdier for Montana for slet ikke at have nogen post for Kansas. Dette hjælper med at demonstrere forskellene i Map.get (Objekt) og Map.containsKey (Object). Fordi ikke alle kortimplementeringstyper tillader nulværdier, omgav jeg den del, der placerer Montana uden en kapital inde i en prøve / fangst-blok.

Resultaterne af at køre de fire typer kort gennem koden vises derefter.

17. aug. 2010 23:23:26 dustin.examples.MapContainsGet logMapInfo INFO: HashMap: {MONTANA = null, WASHINGTON = Olympia, ARIZONA = Phoenix, CALIFORNIA = Sacramento, WYOMING = Cheyenne, SOUTH_DAKOTA = Pierre, COLORADO = Denver, = Sante Fe, NORTH_DAKOTA = Bismark, NEVADA = Carson City, OREGON = Salem, UTAH = Salt Lake City, IDAHO = Boise} 17. aug. 2010 23:23:26 dustin.examples.MapContainsGet demonstrGetAndContains INFO: Kort over typen java. util.HashMap returnerer null for Map.get () ved hjælp af Montana Kort af typen java.util.HashMap returnerer true for Map.containsKey () ved hjælp af Montana Kort af typen java.util.HashMap returnerer null for Map.get () ved hjælp af Kansas Map af typen java.util.HashMap returnerer falsk for Map.containsKey () ved hjælp af 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: Kort af typen java.util.LinkedHashMap returnerer null til Map.get () ved hjælp af Montana Map af typen java .util.LinkedHashMap returnerer sandt for Map.containsKey () ved hjælp af Montana Kort af typen java.util.LinkedHashMap returnerer null for Map.get () ved hjælp af Kansas Kort af typen java.util.LinkedHashMap returnerer falsk for Map.containsKey () ved hjælp af Kansas 17. august 2010 23:23:26 dustin.examples.MapContainsGet createStatesMap SEVERE: java.util.concurrent.ConcurrentHashMap tillader ikke nulværdier - 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_MEXICO = Sante Fe, Sante Fe, Sante Fe, SAD , WASHINGTON = Olympia, NEVADA = Carson City} 17. august 2010 23:23:26 dustin.examples.Ma pContainsGet demonstrGetAndContains INFO: Kort af typen java.util.concurrent.ConcurrentHashMap returnerer null for Map.get () ved hjælp af Montana Kort af typen java.util.concurrent.ConcurrentHashMap returnerer falsk for Map.containsKey () ved hjælp af Montana Map af typen java.util .concurrent.ConcurrentHashMap returnerer null for Map.get () ved hjælp af Kansas Map af typen java.util.concurrent.ConcurrentHashMap returnerer false for Map.containsKey () ved hjælp af 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: Kort af typen java.util.EnumMap returnerer null for Map.get () ved hjælp af Montana Map af typen java.util.EnumMap returnerer true for Map.containsKey () ved hjælp af Montana Map of ty pe java.util.EnumMap returnerer null for Map.get () ved hjælp af Kansas Kort af typen java.util.EnumMap returnerer false for Map.containsKey () ved hjælp af Kansas 

For de tre korttyper, som jeg var i stand til at indtaste nulværdier for, returnerer Map.get (Object) -opkaldet null, selv når den indeholderKey (Object) -metoden returnerer "sand" for Montana, fordi jeg satte den nøgle på kortet uden en værdi. For Kansas er resultaterne konsekvent Map.get () returnerer null og Map.containsKey () returnerer "false", fordi der overhovedet ikke er nogen post i Maps for Kansas.

Outputtet ovenfor viser også, at jeg ikke kunne lægge en nulværdi for Montanas hovedstad i ConcurrentHashMap implementering (en NullPointerException blev kastet).

17. aug. 2010 23:23:26 dustin.examples.MapContainsGet createStatesMapSEVERE: java.util.concurrent.ConcurrentHashMap tillader ikke nulværdier - java.lang.NullPointerException

Dette havde bivirkningen ved at holde Map.get (Objekt) og Map.containsKey (Object) en mere ensartet respektiv null og falsk returværdi. Med andre ord var det umuligt at have en nøgle på kortet uden at have en tilsvarende ikke-nul-værdi.

I mange tilfælde, brug af Map.get (Objekt) fungerer efter behov til de særlige behov ved hånden, men det er bedst at huske, at der er forskelle mellem Map.get (Objekt) og Map.containsKey (Object) for at sikre, at den rette altid bruges. Det er også interessant at bemærke, at Map har et lignende indeholderVærdi (objekt) metode også.

Jeg viser hele kodelisten til MapContainsGet-klassen her for fuldstændighed:

MapContainsGet.java