Collections.emptyMap () vs HashMap baru ()


143

Apa sajakah situasi di mana saya dapat menggunakan Collections.emptyMap()? Dokumentasi mengatakan saya bisa menggunakan metode ini jika saya ingin koleksi saya tidak berubah.

Mengapa saya ingin koleksi kosong abadi? Apa intinya?


12
Memberi +1 pada pertanyaan karena saya belum pernah melihat metode statis sebelumnya
Tim Bender

Anda mungkin juga melihat lensa scala google scala lens . BlankMap dan immutableMap dapat digunakan untuk membuat objek, yang tidak berubah. blankMap adalah titik awal. Setiap kali elemen ditambahkan peta itu sendiri digantikan oleh peta yang mengandung elemen lama dan elemen baru. Intinya, akses ke objek itu aman.
michael_s

1
Ini seperti Objective-C [NSArray array], itu mengembalikan objek yang meskipun tidak dapat digunakan tetapi ada. Jadi Anda bisa bermain dengannya seperti objek normal dan tidak mendapatkan kesalahan.
Shane Hsu

Jawaban:


144

Dari Jawa Efektif , Item # 43 - "Return empty arrays or collections, not null"menunjukkan kembali koleksi kosong dan bahkan mungkin menunjukkan menggunakan ini emptyList(), emptySet()dan emptyMap()metode pada kelas Koleksi untuk mendapatkan koleksi kosong yang juga memiliki manfaat tambahan yang abadi. Dari Item # 15 "Minimize Mutability" .

Dari Collections-emptySet-Collections-blankList-Collections

Ini adalah jenis idiom pemrograman. Ini untuk orang yang tidak ingin variabel nol. Jadi sebelum set diinisialisasi, mereka dapat menggunakan set kosong.

Catatan: Kode di bawah ini hanya sebuah contoh (ubah sesuai dengan kasus penggunaan Anda):

private Set myset = Collections.emptySet();

void initSet() {
   myset = new HashSet();
}
void deleteSet() {
   myset = Collections.emptySet();
}

Metode-metode ini menawarkan beberapa keuntungan:

  1. Mereka lebih ringkas karena Anda tidak perlu mengetik secara eksplisit jenis umum koleksi - itu biasanya hanya disimpulkan dari konteks pemanggilan metode.

  2. Mereka lebih efisien karena mereka tidak repot-repot membuat objek baru; mereka hanya menggunakan kembali objek kosong dan tidak ada yang sudah ada. Efek ini umumnya sangat kecil, tetapi kadang-kadang (yah, jarang) penting.


15
+1 untuk referensi Java yang Efektif. Satu nit: Saya akan merekomendasikan parameterisasi Setdan HashSetdalam contoh Anda, karena seluruh titik emptySet()metode dan teman-teman (yang bertentangan dengan konstanta Collections.EMPTY_SETdll) adalah bahwa mereka bermain bagus dengan obat generik. Plus, menggunakan fitur (tipe mentah) yang sudah usang sejak Java 5 bukan alat bantu mengajar yang baik.
Daniel Pryden

4
Saya tetap tidak yakin ... Bukankah seluruh titik menggunakan Collectionbukannya nulluntuk Exceptionsdilempar pada operasi berikut? Menggunakan koleksi yang tidak berubah hanya akan menghasilkan semacam pengecualian lain yang saya bayangkan. Dan menugaskan nulltentu saja tidak kurang efisien daripada menugaskan konstanta yang tidak dapat diubah.
fgysin mengembalikan Monica

14
@ fgysin: Jika Anda memiliki API tempat klien diharapkan untuk memodifikasi koleksi, maka ya, tidak masuk akal untuk mengembalikan koleksi yang tidak dapat diubah. Tetapi jika Anda memiliki API tempat Anda mengembalikan koleksi yang tidak boleh diubah oleh klien dan harus diulangi saja, maka mengembalikan tampilan ke koleksi yang mendasarinya sangat masuk akal untuk memastikan bahwa klien "buruk" tidak secara tidak sengaja memodifikasi koleksi yang dimiliki oleh Anda. Mengembalikan koleksi kosong bukannya nol berarti bahwa klien Anda tidak perlu melakukan pemeriksaan nol sebelum menggunakan koleksi, membuat kode klien lebih jelas.
Jean Hominal

4
public boolean setExists() { return !myset.equals(Collections.emptySet()); }
assylias

5
Dalam contoh Anda, Anda secara eksplisit memeriksa set kosong dan menggunakannya sebagai nilai sentinel, dan kelas Anda bisa berubah. Contoh kecil Anda menggunakan sentinel dan mutabilitas, yang persisnya ingin dicegah oleh Collections.emptySet ().
Marc O'Morain

33

Memang, menurut pengalaman pribadi saya, sangat berguna jika API membutuhkan kumpulan parameter, tetapi Anda tidak punya apa-apa untuk diberikan. Misalnya, Anda mungkin memiliki API yang terlihat seperti ini, dan tidak mengizinkan referensi nol:

public ResultSet executeQuery(String query, Map<String, Object> queryParameters);

Jika Anda memiliki kueri yang tidak mengambil parameter apa pun, tentu agak boros untuk membuat HashMap, yang melibatkan pengalokasian array, ketika Anda bisa meneruskan 'Empty Map' yang secara efektif merupakan konstanta, cara penerapannya di java.util.Collections.


22

Mengapa saya ingin koleksi kosong abadi? Apa intinya?

Ada dua konsep berbeda di sini yang tampak aneh ketika dilihat bersama. Lebih masuk akal bila Anda memperlakukan kedua konsep secara terpisah.

  • Pertama, Anda harus memilih untuk menggunakan koleksi abadi daripada yang bisa berubah kapan saja. Manfaat immuablity didokumentasikan dengan baik di tempat lain .

  • Kedua, Anda harus memilih untuk menggunakan koleksi kosong daripada menggunakan null sebagai penjaga. Ini dijelaskan dengan baik di sini . Ini berarti Anda akan memiliki kode yang lebih bersih, lebih mudah dipahami, dengan lebih sedikit tempat untuk disembunyikan bug.

Jadi, ketika Anda memiliki kode yang memerlukan peta, lebih baik melewati peta kosong daripada nol untuk menunjukkan tidak adanya peta. Dan sebagian besar waktu ketika Anda menggunakan peta, lebih baik menggunakan peta abadi. Jadi inilah mengapa ada fungsi kenyamanan untuk membuat peta kosong yang tidak dapat diubah.


8

Ada beberapa kasus di mana Anda lebih suka menggunakan peta yang tidak dapat diubah, daftar, set atau jenis koleksi lainnya.

Kasus penggunaan pertama dan yang paling penting adalah setiap kali Anda mengembalikan hasil kueri atau perhitungan yang akan mengembalikan set (atau daftar atau peta) hasil, Anda harus memilih untuk menggunakan struktur data yang tidak dapat diubah.

Dalam hal ini, saya lebih suka mengembalikan versi yang tidak dapat diubah ini karena ini mencerminkan ketidakmampuan faktual dari resultset dari perhitungan yang jauh lebih jelas - tidak peduli apa yang Anda lakukan dengan data nanti, set hasil yang Anda terima dari permintaan Anda seharusnya tidak perubahan.

Kasus penggunaan umum kedua adalah ketika Anda harus memberikan argumen sebagai input untuk metode atau layanan. Kecuali jika Anda mengharapkan pengumpulan input akan dimodifikasi oleh layanan atau metode (yang biasanya merupakan ide desain yang sangat buruk), meneruskan koleksi yang tidak dapat diubah dan bukan yang dapat diubah mungkin merupakan pilihan yang masuk akal dan aman dalam banyak kasus.

Saya menganggapnya sebagai konvensi "lewat nilai" .

Lebih umum - ini adalah praktik yang masuk akal untuk menggunakan struktur data yang tidak berubah kapan pun data melintasi modul atau batas layanan. Ini membuatnya lebih mudah untuk alasan tentang perbedaan antara input / output (tidak berubah) dan keadaan internal yang bisa berubah.

Sebagai efek samping yang sangat menguntungkan dari hal ini adalah peningkatan keamanan dan keselamatan utas modul / layanan Anda dan memastikan pemisahan masalah yang lebih bersih.

Alasan lain yang baik untuk menggunakan Collections.empty*()metode adalah kurangnya verboseness mereka. Di era pra-Java7, jika Anda memiliki koleksi generik, Anda harus menaburkan anotasi tipe generik di semua tempat.

Bandingkan saja kedua deklarasi ini:

Map<Foo, Comparable<? extends Bar>> fooBarMap = new HashMap<Foo, Comparable<? extends Bar>>();

melawan:

Map<Foo, Comparable<? extends Bar>> fooBarMap = Collections.emptyMap();

Yang terakhir jelas memenangkan keterbacaan dengan dua cara penting:

  1. Dalam deklarasi pertama, seluruh instantiation dari peta kosong dikubur dalam kebisingan deklarasi tipe generik, membuat deklarasi yang pada dasarnya sepele jauh lebih samar daripada yang seharusnya.
  2. Selain kurangnya penjelasan jenis umum di sisi kanan, versi kedua dengan jelas menyatakan bahwa peta diinisialisasi ke peta kosong. Selain itu - mengetahui bahwa metode ini mengembalikan peta yang tidak dapat diubah, sekarang lebih mudah bagi saya untuk menemukan di mana fooBarMapdiberikan nilai non-kosong lain hanya dengan mencari /fooBarMap =/.

5

Untuk satu, Anda bisa lolos dengan berbagi referensi. Sebuah new HashMap()dll akan memerlukan objek yang dialokasikan, dan mungkin beberapa elemen tambahan untuk menyimpan data, tapi Anda hanya perlu satu salinan dari koleksi abadi kosong (daftar, set, peta, atau seperti lainnya). Ini membuatnya menjadi pilihan yang jelas ketika metode yang Anda panggil perlu menerima Peta tetapi tidak perlu mengeditnya.

Saya sarankan memeriksa Java Efektif Josh Bloch , yang mencantumkan beberapa atribut yang sangat bagus dari objek yang tidak dapat diubah (termasuk keamanan utas).


3

Ini dapat berguna ketika Anda memiliki fungsi yang mengembalikan immutable collectiondan dalam beberapa situasi tidak ada data untuk dikembalikan jadi alih-alih kembali nullAnda dapat mengembalikanemptyMap()

Itu membuat kode Anda lebih mudah dan mencegah NullPointerException


3

Sebagian besar waktu kita gunakan constructoruntuk membuat yang baru empty map. Tetapi Collections methodsmenawarkan beberapa keuntungan untuk membuat empty mappenggunaanstatic method java.util.Collections.emptyMap()

  1. Mereka lebih ringkas karena Anda tidak perlu mengetik secara eksplisit jenis umum koleksi - itu biasanya hanya disimpulkan dari konteks pemanggilan metode.

  2. Mereka lebih efisien karena mereka tidak repot-repot membuat objek baru; mereka hanya menggunakan kembali objek kosong dan tidak ada yang sudah ada. Efek ini umumnya sangat kecil, tetapi kadang-kadang (yah, jarang) penting.


2

Mengapa saya ingin koleksi kosong abadi? Apa intinya?

Untuk alasan yang sama Anda akan gunakan Collections.unmodifiableMap()di beberapa titik. Anda ingin mengembalikan instance Peta yang melempar pengecualian jika pengguna mencoba mengubahnya. Ini hanya kasus khusus: Peta kosong.


1

Mengapa saya ingin koleksi kosong abadi? Apa intinya?

Untuk alasan yang sama mengapa Anda mungkin menginginkan benda yang tidak dapat diubah. Terutama karena Anda dapat tidur dengan aman di malam hari dalam pengetahuan bahwa banyak utas dapat mengakses instance objek yang sama dan bahwa mereka semua akan melihat nilai yang sama. Tidak memiliki item dalam koleksi masih merupakan nilai yang valid, yang ingin Anda pertahankan.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.