Peta Java.get dan Peta.containsKey

Ketika menggunakan implementasi Peta Java, kadang-kadang biasa untuk menggunakan Mapmetode get (Object) dan bereaksi secara berbeza berdasarkan apakah nilai yang dikembalikan adalah nol atau tidak. Anggapan umum mungkin dibuat bahawa nol yang dikembalikan dari Map.get (Object) menunjukkan bahawa tidak ada entri dengan kunci yang disediakan di peta, tetapi ini tidak selalu berlaku. Memang, jika Mapimplementasi Java memungkinkan nilai null, maka mungkin untuk Mapmengembalikan nilainya untuk kunci yang diberikan, tetapi nilai itu mungkin nol. Selalunya ini tidak menjadi masalah, tetapi jika berlaku, seseorang boleh menggunakan Map.containsKey () untuk menentukan sama ada Mapentri mempunyai entri kunci. Sekiranya ia berlaku dan Mappengembalian nullpanggilan masuk untuk kunci yang sama, maka kemungkinan kunci itu memetakan ke anullnilai. Dengan kata lain, itu Mapmungkin kembali "benar" untuk containsKey(Object)sementara pada masa yang sama kembali " null" untuk get(Object). Terdapat beberapa Mappelaksanaan yang tidak membenarkan nullnilai. Dalam kes tersebut, panggilan nulldari "get" secara konsisten harus sesuai dengan pengembalian "false" dari kaedah "mengandungKey".

Dalam catatan blog ini, saya menunjukkan aspek-aspek ini  Map.get(Object)dan Map.containsKey(Object). Sebelum pergi ke demonstrasi itu, pertama saya akan menunjukkan bahawa dokumentasi Javadoc untuk Map.get (Object) secara tegas memberi amaran tentang perbezaan halus antara Map.get(Object)dan Map.containsKey(Object):

Sekiranya peta ini membenarkan nilai nol, maka nilai pengembalian  null tidak semestinya menunjukkan bahawa peta tidak mengandungi pemetaan untuk kunci; ada kemungkinan peta secara jelas memetakan kunci untuk  null. The  containsKey operasi boleh digunakan untuk membezakan kedua-dua kes.

Untuk contoh catatan, saya akan menggunakan enum Negeri yang ditentukan seterusnya:

Negeri.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; } } 

Penyenaraian kod seterusnya menggunakan enum di atas dan mengisi peta negeri ke ibu kota mereka. Kaedah ini menerima Kelas yang seharusnya merupakan implementasi khusus Peta yang akan dihasilkan dan dihuni.

menghasilkanStatesMap (Kelas)

/** * 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; } 

Kaedah di atas boleh digunakan untuk menghasilkan Peta pelbagai jenis. Saya tidak menunjukkan kodnya sekarang, tetapi contoh saya membuat Peta ini dengan empat pelaksanaan khusus: HashMap, LinkedHashMap, ConcurrentHashMap, dan EnumMap. Setiap empat pelaksanaan ini kemudian dijalankan melalui kaedah demonstrateGetAndContains(Map), yang ditunjukkan seterusnya.

demonstrGetAndContains (Peta)

/** * 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()); } 

Untuk demonstrasi ini, saya dengan sengaja menyiapkan Peta agar mempunyai nilai modal kosong untuk Montana tidak mempunyai entri sama sekali untuk Kansas. Ini membantu menunjukkan perbezaan dalam Map.get(Object)dan Map.containsKey(Object). Oleh kerana tidak setiap jenis implementasi Peta memungkinkan nilai nol, saya mengepung bahagian yang menempatkan Montana tanpa modal di dalam blok try / catch.

Hasil menjalankan empat jenis Peta melalui kod muncul seterusnya.

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 

Untuk tiga jenis Peta yang saya dapat memasukkan nilai nol, panggilan Map.get (Object) mengembalikan null walaupun kaedah mengandungKey (Object) mengembalikan "true" untuk Montana kerana saya meletakkan kunci itu dalam peta tanpa nilai. Untuk Kansas, hasilnya secara konsisten Map.get () mengembalikan null dan Map.containsKey () mengembalikan "false" kerana tidak ada entri sama sekali di Maps untuk Kansas.

Hasil di atas juga menunjukkan bahawa saya tidak dapat meletakkan nilai nol untuk modal Montana ke dalam ConcurrentHashMappelaksanaan (NullPointerException dilemparkan).

Aug 17, 2010 11:23:26 PM dustin.examples.MapContainsMendapatkanStatesMapSEVERE: java.util.concurrent.ConcurrentHashMap tidak membenarkan nilai null - java.lang.NullPointerException

Ini mempunyai kesan sampingan dari menjaga Map.get(Object)dan Map.containsKey(Object)nilai pulangan yang tidak betul dan salah masing-masing yang lebih konsisten. Dengan kata lain, mustahil untuk mempunyai kunci dalam peta tanpa mempunyai nilai bukan nol yang sesuai.

Dalam banyak kes, penggunaan Map.get(Object)karya sesuai keperluan untuk keperluan tertentu yang ada, tetapi sebaiknya diingat bahawa ada perbezaan antara Map.get(Object)dan Map.containsKey(Object)memastikan yang sesuai selalu digunakan. Juga menarik untuk diperhatikan bahawa Peta mempunyai containsValue(Object)kaedah yang serupa juga.

Saya menyenaraikan keseluruhan senarai kod untuk kelas MapContainsGet di sini untuk kelengkapan:

MapContainsGet.java