Bagaimana Anda menginisialisasi statis Map
di Jawa?
Metode satu: penginisialisasi statis
Metode dua: penginisialisasi instance (subclass anonim) atau metode lain?
Apa pro dan kontra dari masing-masing?
Berikut adalah contoh yang menggambarkan dua metode:
import java.util.HashMap;
import java.util.Map;
public class Test {
private static final Map<Integer, String> myMap = new HashMap<>();
static {
myMap.put(1, "one");
myMap.put(2, "two");
}
private static final Map<Integer, String> myMap2 = new HashMap<>(){
{
put(1, "one");
put(2, "two");
}
};
}
Map.of
lainMap.ofEntries
, periksa stackoverflow.com/a/37384773/1216775Jawaban:
Inisialisasi instance hanya gula sintaksis dalam kasus ini, kan? Saya tidak mengerti mengapa Anda perlu kelas anonim tambahan hanya untuk menginisialisasi. Dan itu tidak akan berhasil jika kelas yang dibuat adalah final.
Anda dapat membuat peta abadi menggunakan penginisialisasi statis juga:
sumber
Saya suka cara Jambu menginisialisasi peta statis yang tidak dapat diubah:
Seperti yang Anda lihat, ini sangat ringkas (karena metode pabrik yang mudah digunakan
ImmutableMap
).Jika Anda ingin peta memiliki lebih dari 5 entri, Anda tidak dapat lagi menggunakan
ImmutableMap.of()
. Alih-alih, cobaImmutableMap.builder()
di bawah ini:Untuk mempelajari lebih lanjut tentang manfaat dari utilitas pengumpulan yang tidak berubah oleh Guava, lihat Koleksi Tidak Berubah yang Dijelaskan dalam Panduan Pengguna Guava .
(Subset dari) Jambu biji dulu disebut Google Collections . Jika Anda belum menggunakan pustaka ini dalam proyek Java Anda, saya sangat merekomendasikan untuk mencobanya! Guava dengan cepat menjadi salah satu libs pihak ke-3 gratis yang paling populer dan bermanfaat untuk Java, seperti yang disetujui oleh sesama pengguna SO . (Jika Anda baru mengenalnya, ada beberapa sumber belajar yang sangat baik di balik tautan itu.)
Pembaruan (2015) : Adapun Java 8 , well, saya masih akan menggunakan pendekatan Guava karena jauh lebih bersih daripada yang lain. Jika Anda tidak ingin ketergantungan jambu biji, pertimbangkan metode init lama biasa . Peretasan dengan array dua dimensi dan Stream API sangat jelek jika Anda bertanya kepada saya, dan menjadi lebih buruk jika Anda perlu membuat Peta yang kunci dan nilainya bukan tipe yang sama (seperti
Map<Integer, String>
dalam pertanyaan).Adapun masa depan Guava secara umum, sehubungan dengan Java 8, Louis Wasserman mengatakan ini kembali pada tahun 2014, dan [ pembaruan ] pada tahun 2016 diumumkan bahwa Guava 21 akan membutuhkan dan mendukung Java 8 dengan baik .
Pembaruan (2016) : Seperti yang ditunjukkan Tagir Valeev , Java 9 pada akhirnya akan membuat hal ini bersih dengan menggunakan JDK murni, dengan menambahkan metode pabrik yang praktis untuk koleksi:
sumber
Saya akan menggunakan:
sumber
Java 5 menyediakan sintaks yang lebih ringkas ini:
sumber
HashMap implements Serializable
. Karena Anda benar-benar membuat subkelas HashMap menggunakan "trik" ini, Anda secara implisit membuat kelas Serializable. Dan untuk ini, Anda harus menyediakan serialUID.Double brace initialization can cause memory leaks when used from a non-static context, because the anonymous class created will maintain a reference to the surrounding object. It has worse performance than regular initialization because of the additional class loading required. It can cause equals() comparisons to fail, if the equals() method does not accept subclasses as parameter. And finally, pre Java 9 it cannot be combined with the diamond operator, because that cannot be used with anonymous classes.
- IntelliJHashMap.equals
didefinisikanAbstractMap
dan bekerja pada subkelas Peta apa pun , jadi itu bukan masalah di sini. Masalahnya, operator berlian mengganggu, tetapi seperti yang disebutkan sekarang telah diselesaikan.Satu keuntungan dari metode kedua adalah Anda dapat membungkusnya dengan
Collections.unmodifiableMap()
untuk memastikan bahwa tidak ada yang akan memperbarui koleksi nanti:sumber
Berikut adalah penginisialisasi peta statis satu baris Java 8:
Sunting: untuk menginisialisasi a
Map<Integer, String>
seperti pada pertanyaan, Anda memerlukan sesuatu seperti ini:Sunting (2): Ada versi yang lebih baik, tipe campuran yang mampu oleh i_am_zero yang menggunakan aliran
new SimpleEntry<>(k, v)
panggilan. Lihat jawaban itu: https://stackoverflow.com/a/37384773/3950982sumber
String[][]
tidak perlu,Object[][]
diperlukan). IMHO, pendekatan ini jelek (apalagi dengan gips) dan sulit diingat; tidak akan menggunakannya sendiri.Map.of
di Jawa 9+Lihat JEP 269 untuk detailnya. JDK 9 mencapai ketersediaan umum pada bulan September 2017.
sumber
Map.ofEntries
Jawa 9
Kita dapat menggunakan
Map.ofEntries
, memanggilMap.entry( k , v )
untuk membuat setiap entri.Kita juga dapat menggunakan
Map.of
seperti yang disarankan oleh Tagir dalam jawabannya di sini tetapi kita tidak dapat menggunakan lebih dari 10 entriMap.of
.Java 8 (Solusi Rapi)
Kami dapat membuat Stream entri peta. Kita sudah memiliki dua implementasi dari
Entry
dalamjava.util.AbstractMap
yang SimpleEntry dan SimpleImmutableEntry . Untuk contoh ini kita dapat menggunakan yang pertama sebagai:sumber
new SimpleEntry<>()
cara adalah jauh lebih mudah dibaca daripada statisput()
: /Dengan Eclipse Collections , semua hal berikut ini akan berfungsi:
Anda juga dapat secara statis menginisialisasi peta primitif dengan Eclipse Collections.
Catatan: Saya pengendara untuk Eclipse Collections
sumber
Saya tidak akan pernah membuat subclass anonim dalam situasi ini. Inisialisasi statis berfungsi sama baiknya, jika Anda ingin membuat peta tidak dapat dimodifikasi, misalnya:
sumber
Mungkin menarik untuk memeriksa Google Collections , misalnya video yang mereka miliki di halaman mereka. Mereka menyediakan berbagai cara untuk menginisialisasi peta dan set, dan juga menyediakan koleksi yang tidak berubah.
Pembaruan: Perpustakaan ini sekarang bernama Guava .
sumber
Saya suka kelas anonim, karena mudah ditangani:
sumber
Jika kita mendeklarasikan lebih dari satu konstanta maka kode itu akan ditulis dalam blok statis dan itu sulit dipertahankan di masa depan. Jadi lebih baik menggunakan kelas anonim.
Dan disarankan untuk menggunakan peta yang tidak dapat dimodifikasi untuk konstanta selain itu tidak dapat diperlakukan sebagai konstanta.
sumber
Saya sangat menyarankan gaya "inisialisasi penjepit ganda" atas gaya blok statis.
Seseorang mungkin berkomentar bahwa mereka tidak suka kelas anonim, overhead, kinerja, dll.
Tapi yang lebih saya pertimbangkan adalah pembacaan kode dan rawatan. Dalam sudut pandang ini, saya berdiri penyangga ganda adalah gaya kode yang lebih baik daripada metode statis.
Selain itu, jika Anda mengetahui GC dari kelas anonim, Anda selalu dapat mengonversinya menjadi HashMap normal dengan menggunakan
new HashMap(Map map)
.Anda dapat melakukan ini sampai Anda menghadapi masalah lain. Jika ya, Anda harus menggunakan melengkapi gaya pengkodean lain (mis. Tidak ada kelas statis, pabrik) untuk itu.
sumber
Seperti biasa apache-commons memiliki metode MapUtils.putAll (Map, Object []) yang tepat :
Misalnya, untuk membuat peta warna:
sumber
Arrays.asMap( ... )
di Java, saya pikir ini adalah solusi terbaik. Menciptakan kembali roda biasanya konyol. Kelemahan sangat kecil adalah bahwa dengan obat generik akan memerlukan konversi yang tidak dicentang.SuppressWarnings( unchecked )
di Eclipse dengan garis sepertiMap<String, String> dummy = MapUtils.putAll(new HashMap<String, String>(), new Object[][]... )
String[][]
saya mendapatkan "peringatan"! Dan tentu saja itu hanya bekerja jika AndaK
danV
kelas yang sama. Saya kira Anda belum (secara dimengerti) mengatur "konversi yang tidak dicentang" menjadi "Abaikan" di pengaturan Eclipse Anda?Inilah favorit saya ketika saya tidak ingin (atau tidak bisa) menggunakan Guava
ImmutableMap.of()
, atau jika saya perlu bisa berubahMap
:Ini sangat kompak, dan mengabaikan nilai-nilai liar (yaitu kunci terakhir tanpa nilai).
Pemakaian:
sumber
Jika Anda ingin peta yang tidak dapat dimodifikasi, akhirnya java 9 menambahkan metode pabrik keren
of
keMap
antarmuka. Metode serupa ditambahkan ke Set, List juga.Map<String, String> unmodifiableMap = Map.of("key1", "value1", "key2", "value2");
sumber
Saya lebih suka menggunakan penginisialisasi statis untuk menghindari menghasilkan kelas anonim (yang tidak memiliki tujuan lebih lanjut), jadi saya akan daftar tips inisialisasi dengan penginisialisasi statis. Semua solusi / tip yang tercantum adalah tipe-aman.
Catatan: Pertanyaannya tidak mengatakan apa pun tentang membuat peta tidak dapat dimodifikasi, jadi saya akan mengabaikannya, tetapi tahu bahwa itu dapat dengan mudah dilakukan
Collections.unmodifiableMap(map)
.Kiat pertama
Kiat pertama adalah Anda dapat membuat referensi lokal ke peta dan Anda memberinya nama PENDEK:
Tip kedua
Kiat kedua adalah Anda bisa membuat metode pembantu untuk menambahkan entri; Anda juga dapat membuat metode penolong ini menjadi publik jika Anda ingin:
Metode helper di sini tidak dapat digunakan kembali karena hanya dapat menambahkan elemen
myMap2
. Untuk membuatnya dapat digunakan kembali, kita bisa menjadikan peta itu sendiri sebagai parameter dari metode helper, tetapi kemudian kode inisialisasi tidak akan lebih pendek.Tip ketiga
Kiat ke-3 adalah Anda dapat membuat kelas pembantu seperti pembangun yang dapat digunakan kembali dengan fungsionalitas populating. Ini benar-benar kelas pembantu sederhana 10-baris yang aman untuk jenis:
sumber
Kelas anonim yang Anda buat berfungsi dengan baik. Namun Anda harus menyadari bahwa ini adalah kelas dalam dan karenanya, itu akan berisi referensi ke instance kelas sekitarnya. Jadi Anda akan menemukan bahwa Anda tidak dapat melakukan hal-hal tertentu dengannya (menggunakan XStream untuk satu). Anda akan mendapatkan beberapa kesalahan yang sangat aneh.
Karena itu, selama Anda sadar maka pendekatan ini baik-baik saja. Saya menggunakannya sebagian besar waktu untuk menginisialisasi semua jenis koleksi secara ringkas.
EDIT: Tunjukkan dengan benar di komentar bahwa ini adalah kelas statis. Jelas saya tidak cukup membaca ini. Namun komentar saya lakukan masih berlaku untuk kelas batin anonim.
sumber
Jika Anda menginginkan sesuatu yang singkat dan relatif aman, Anda bisa mengubah pemeriksaan tipe kompilasi menjadi run-time:
Implementasi ini harus menangkap kesalahan:
sumber
Dengan Java 8 saya datang untuk menggunakan pola berikut:
Ini bukan yang paling singkat dan agak bundaran, tapi
java.util
sumber
toMap
tanda tangan termasuk pemasok peta untuk menentukan jenis peta.Jika Anda hanya perlu menambahkan satu nilai ke peta, Anda dapat menggunakan Collections.singletonMap :
sumber
Anda dapat menggunakan
StickyMap
danMapEntry
dari Cactoos :sumber
Pendekatan kedua Anda (inisialisasi Double Brace) dianggap sebagai pola anti , jadi saya akan menggunakan pendekatan pertama.
Cara mudah lain untuk menginisialisasi Peta statis adalah dengan menggunakan fungsi utilitas ini:
Catatan:
Java 9
Anda dapat menggunakan Map.ofsumber
Saya tidak suka sintaks initializer Static dan saya tidak yakin dengan subclass anonim. Secara umum, saya setuju dengan semua kontra menggunakan inisialisasi Static dan semua kontra menggunakan subclass anonim yang disebutkan dalam jawaban sebelumnya. Di sisi lain - pro yang disajikan dalam posting ini tidak cukup untuk saya. Saya lebih suka menggunakan metode inisialisasi statis:
sumber
Saya belum melihat pendekatan yang saya gunakan (dan semakin menyukai) yang diposting dalam jawaban apa pun, jadi ini dia:
Saya tidak suka menggunakan inisialisasi statis karena mereka kikuk, dan saya tidak suka kelas anonim karena membuat kelas baru untuk setiap contoh.
sebagai gantinya, saya lebih suka inisialisasi yang terlihat seperti ini:
sayangnya, metode ini bukan bagian dari pustaka Java standar, jadi Anda perlu membuat (atau menggunakan) pustaka utilitas yang mendefinisikan metode berikut:
(Anda dapat menggunakan 'impor statis' untuk menghindari keharusan awalan nama metode)
Saya merasa bermanfaat untuk menyediakan metode statis yang serupa untuk koleksi lainnya (daftar, set, setel Urutkan, Urutkan Peta, dll.)
Ini tidak sebagus inisialisasi objek json, tapi ini adalah langkah ke arah itu, sejauh menyangkut keterbacaan.
sumber
Karena Java tidak mendukung peta literal, instance peta harus selalu dibuat secara eksplisit dan dihuni.
Untungnya, dimungkinkan untuk memperkirakan perilaku literal peta di Jawa menggunakan metode pabrik .
Sebagai contoh:
Keluaran:
Ini jauh lebih nyaman daripada membuat dan mengisi elemen peta pada suatu waktu.
sumber
JEP 269 menyediakan beberapa metode pabrik praktis untuk Collections API. Metode pabrik ini tidak dalam versi Java saat ini, yaitu 8, tetapi direncanakan untuk rilis Java 9.
Karena
Map
ada dua metode pabrik:of
danofEntries
. Menggunakanof
, Anda dapat melewati pasangan kunci / nilai bolak-balik. Misalnya, untuk membuatMap
sejenis{age: 27, major: cs}
:Saat ini ada sepuluh versi kelebihan beban
of
, sehingga Anda dapat membuat peta yang berisi sepuluh pasangan kunci / nilai. Jika Anda tidak menyukai batasan ini atau kunci / nilai yang berganti-ganti, Anda dapat menggunakanofEntries
:Keduanya
of
danofEntries
akan mengembalikan yang tidak berubahMap
, sehingga Anda tidak dapat mengubah elemen mereka setelah konstruksi. Anda dapat mencoba fitur-fitur ini menggunakan JDK 9 Early Access .sumber
Yah ... saya suka enum;)
sumber
Saya sudah membaca jawabannya dan saya memutuskan untuk menulis pembuat peta saya sendiri. Jangan ragu untuk menyalin dan menempel.
EDIT: Akhir-akhir ini, saya terus menemukan metode statis publik
of
cukup sering dan saya agak menyukainya. Saya menambahkannya ke dalam kode dan menjadikan konstruktor sebagai pribadi, sehingga beralih ke pola metode pabrik statis.EDIT2: Bahkan lebih baru-baru ini, saya tidak lagi suka metode statis yang disebut
of
, karena terlihat sangat buruk ketika menggunakan impor statis. Saya mengganti namanya menjadimapOf
, membuatnya lebih cocok untuk impor statis.sumber