Java Map.get dan Map.containsKey

Saat menggunakan implementasi Peta Java, terkadang umum untuk memanggil metode Mapget (Object) dan bereaksi secara berbeda berdasarkan apakah nilai yang dikembalikan adalah null atau tidak. Asumsi umum mungkin dibuat bahwa nilai null yang dikembalikan dari Map.get (Object) menunjukkan tidak ada entri dengan kunci yang disediakan di peta, tapi ini tidak selalu terjadi. Memang, jika Mapimplementasi Java memungkinkan nilai null, maka dimungkinkan untuk Mapmengembalikan nilainya untuk kunci yang diberikan, tetapi nilai itu mungkin nol. Seringkali ini tidak masalah, tetapi jika ya, seseorang dapat menggunakan Map.containsKey () untuk menentukan apakah Mapentri tersebut memiliki entri kunci. Jika ya dan Maphasil nulldari panggilan get untuk kunci yang sama, maka kemungkinan kunci tersebut memetakan ke anullnilai. Dengan kata lain, itu Mapmungkin mengembalikan "benar" untuk containsKey(Object)sementara pada saat yang sama mengembalikan " null" untuk get(Object). Ada beberapa Mapimplementasi yang tidak mengizinkan nullnilai. Dalam kasus tersebut, panggilan nulldari "get" harus secara konsisten cocok dengan pengembalian "false" dari metode "containsKey".

Dalam posting blog ini, saya mendemonstrasikan aspek-aspek dari  Map.get(Object)dan Map.containsKey(Object). Sebelum masuk ke demonstrasi itu, pertama-tama saya akan menunjukkan bahwa dokumentasi Javadoc untuk Map.get (Object) secara eksplisit memperingatkan tentang perbedaan halus antara Map.get(Object)dan Map.containsKey(Object):

Jika peta ini mengizinkan nilai null, maka nilai yang dikembalikan  null tidak selalu menunjukkan bahwa peta tidak berisi pemetaan untuk kunci tersebut; mungkin juga peta secara eksplisit memetakan kunci ke  null. The  containsKey operasi dapat digunakan untuk membedakan dua kasus ini.

Untuk contoh posting, saya akan menggunakan enum Serikat yang ditentukan selanjutnya:

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

Daftar kode berikutnya menggunakan enum di atas dan mengisi peta negara bagian ke ibu kota mereka. Metode ini menerima Kelas yang harus menjadi implementasi khusus dari Peta yang akan dibuat dan diisi.

generateStatesMap (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; } 

Metode di atas dapat digunakan untuk menghasilkan berbagai macam Peta. Saya tidak menampilkan kodenya sekarang, tetapi contoh saya membuat Maps ini dengan empat implementasi spesifik: HashMap, LinkedHashMap, ConcurrentHashMap, dan EnumMap. Masing-masing dari empat implementasi ini kemudian dijalankan melalui metode demonstrateGetAndContains(Map), yang ditampilkan berikutnya.

demonstrasikanGetAndContains (Map)

/** * 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 sengaja menyiapkan Maps agar memiliki nilai kapital nol agar Montana tidak memiliki entri sama sekali untuk Kansas. Ini membantu untuk menunjukkan perbedaan dalam Map.get(Object)dan Map.containsKey(Object). Karena tidak semua jenis implementasi Peta memungkinkan nilai null, saya mengepung bagian yang menempatkan Montana tanpa modal di dalam blok coba / tangkap.

Hasil menjalankan keempat jenis Maps melalui kode muncul berikutnya.

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 tipe Map yang saya dapat memasukkan nilai null, panggilan Map.get (Object) mengembalikan null bahkan ketika metode containsKey (Object) mengembalikan "true" untuk Montana karena saya meletakkan kunci itu di peta tanpa nilai. Untuk Kansas, hasilnya secara konsisten Map.get () mengembalikan null dan Map.containsKey () mengembalikan "false" karena tidak ada entri apa pun di Maps untuk Kansas.

Output di atas juga menunjukkan bahwa saya tidak dapat memasukkan nilai null untuk modal Montana ke dalam ConcurrentHashMapimplementasi (NullPointerException dilemparkan).

17 Agustus 2010, 11:23:26 PM dustin.examples.MapContainsGet generateStatesMapSEVERE: java.util.concurrent.ConcurrentHashMap tidak mengizinkan nilai null - java.lang.NullPointerException

Ini memiliki efek samping menjaga Map.get(Object)dan Map.containsKey(Object)nilai null dan false return masing-masing lebih konsisten. Dengan kata lain, tidak mungkin memiliki kunci di peta tanpa memiliki nilai bukan nol yang sesuai.

Dalam banyak kasus, penggunaan Map.get(Object)karya seperlunya untuk kebutuhan tertentu yang ada, tetapi yang terbaik adalah mengingat bahwa ada perbedaan antara Map.get(Object)dan Map.containsKey(Object)untuk memastikan yang sesuai selalu digunakan. Menarik juga untuk dicatat bahwa Peta juga memiliki containsValue(Object)metode yang serupa .

Saya mencantumkan seluruh daftar kode untuk kelas MapContainsGet di sini untuk kelengkapan:

MapContainsGet.java