menambahkan beberapa entri ke HashMap sekaligus dalam satu pernyataan

139

Saya perlu menginisialisasi HashMap konstan dan ingin melakukannya dalam pernyataan satu baris. Menghindari sth seperti ini:

  hashMap.put("One", new Integer(1)); // adding value into HashMap
  hashMap.put("Two", new Integer(2));      
  hashMap.put("Three", new Integer(3));

mirip dengan ini di tujuan C:

[NSDictionary dictionaryWithObjectsAndKeys:
@"w",[NSNumber numberWithInt:1],
@"K",[NSNumber numberWithInt:2],
@"e",[NSNumber numberWithInt:4],
@"z",[NSNumber numberWithInt:5],
@"l",[NSNumber numberWithInt:6],
nil] 

Saya belum menemukan contoh apa pun yang menunjukkan bagaimana melakukan ini setelah melihat begitu banyak.

pengguna387184
sumber

Jawaban:

261

Anda dapat menggunakan Inisialisasi Penjepit Ganda seperti yang ditunjukkan di bawah ini:

Map<String, Integer> hashMap = new HashMap<String, Integer>()
{{
     put("One", 1);
     put("Two", 2);
     put("Three", 3);
}};

Sebagai bagian dari peringatan, silakan lihat thread Efisiensi Java "Inisialisasi Penjepit Ganda" untuk implikasi kinerja yang mungkin dimilikinya.

Eng. Fouad
sumber
11
@ user387184 Ya, mereka menyebutnya "penginisialisasi penjepit ganda". Lihat topik ini: stackoverflow.com/questions/924285/…
Eng.Fouad
2
Saya hanya memasukkannya ke dalam kode saya dan saya mendapatkan peringatan / pesan ini di baris: "Kelas serializable tidak menyatakan bidang serialVersionUID akhir statis tipe panjang". Bisakah saya mengabaikannya? Apa artinya ini? Terima kasih
pengguna387184
32
Anda sebaiknya tidak menggunakan metode ini. Ini membuat kelas baru untuk setiap kali Anda menggunakannya, yang memiliki kinerja yang jauh lebih buruk daripada sekadar membuat peta. Lihat stackoverflow.com/questions/924285/…
Timo Türschmann
7
Alasan saya menurunkan suara ini adalah karena tidak menjelaskan bahwa ini membuat kelas baru untuk setiap kali Anda menggunakannya. Saya pikir orang harus menyadari pengorbanan melakukannya dengan cara ini.
idungotnosn
7
@ TimoTürschmann Tampaknya jika saya membutuhkan inisialisasi statis dari peta seperti ini, itu juga akan menjadi statis, menghilangkan setiap kali Anda menggunakannya penalti kinerja - Anda akan mendapat penalti itu sekali. Saya tidak dapat melihat waktu lain bahwa orang akan menginginkan inisialisasi semacam ini tanpa variabel yang statis (misalnya, apakah ada yang pernah menggunakan ini dalam satu lingkaran?). Saya mungkin salah, programmer itu inventif.
Chris Cirefice
68

Anda dapat menggunakan ImmutableMap Google Guava. Ini berfungsi selama Anda tidak peduli tentang memodifikasi Peta nanti (Anda tidak dapat memanggil .put () pada peta setelah membuatnya menggunakan metode ini):

import com.google.common.collect.ImmutableMap;

// For up to five entries, use .of()
Map<String, Integer> littleMap = ImmutableMap.of(
    "One", Integer.valueOf(1),
    "Two", Integer.valueOf(2),
    "Three", Integer.valueOf(3)
);

// For more than five entries, use .builder()
Map<String, Integer> bigMap = ImmutableMap.<String, Integer>builder()
    .put("One", Integer.valueOf(1))
    .put("Two", Integer.valueOf(2))
    .put("Three", Integer.valueOf(3))
    .put("Four", Integer.valueOf(4))
    .put("Five", Integer.valueOf(5))
    .put("Six", Integer.valueOf(6))
    .build();

Lihat juga: http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html

Pertanyaan yang agak terkait: Solusi ImmutableMap.of () untuk HashMap di Maps?

JimmyT
sumber
Jambu biji sangat besar, saya tidak akan menggunakannya untuk aplikasi Android saya kecuali benar-benar diperlukan
ericn
4
Berhati-hatilah karena ImmutableMaptidak menerima nullkunci atau nilai.
Vadzim
@ericn ProGuard memungkinkan Anda mengecualikan setiap bagian dari perpustakaan Anda tidak menggunakan.
dimo414
58

Sejak Java 9, dimungkinkan untuk digunakan Map.of(...), seperti:

Map<String, Integer> immutableMap = Map.of("One", 1, 
                                           "Two", 2, 
                                           "Three", 3);

Peta ini tidak bisa diubah. Jika Anda ingin peta dapat diubah, Anda harus menambahkan:

Map<String, Integer> hashMap = new HashMap<>(immutableMap);

Jika Anda tidak dapat menggunakan Java 9, Anda terjebak dengan menulis sendiri metode pembantu yang serupa atau menggunakan pustaka pihak ketiga (seperti Guava ) untuk menambahkan fungsionalitas itu untuk Anda.

Timo Türschmann
sumber
Setelah menambahkan 10 entri, itu melempar kesalahan aneh "tidak dapat menyelesaikan metode", apakah bug ini dengan metode ini?
vikramvi
3
@vikramvi ya Jika Anda melihat dokumentasi Map.of hanya dilakukan hingga 10 entri karena cukup melelahkan
jolivier
9

Peta juga memiliki metode pabrik yang ditambahkan di Java 9. Untuk hingga 10 entri, Peta telah membebani konstruktor yang mengambil pasangan kunci dan nilai. Misalnya kita bisa membangun peta berbagai kota dan populasinya (menurut google pada Oktober 2016) sebagai berikut:

Map<String, Integer> cities = Map.of("Brussels", 1_139000, "Cardiff", 341_000);

Kasus var-args untuk Map sedikit lebih sulit, Anda harus memiliki kunci dan nilai, tetapi di Java, metode tidak dapat memiliki dua parameter var-args. Jadi kasus umum ditangani dengan mengambil metode Map.Entry<K, V>objek var-args dan menambahkan entry()metode statis yang menyusunnya. Sebagai contoh:

Map<String, Integer> cities = Map.ofEntries(
    entry("Brussels", 1139000), 
    entry("Cardiff", 341000)
);

Metode Pabrik Pengumpulan di Jawa 9

Sadiq Ali
sumber
Luar biasa jika Anda bisa menggunakan Java 9+. Juga metode pabrik ini mengembalikan peta yang tidak dapat diubah.
Sourabh
8

Java tidak memiliki peta literal, jadi tidak ada cara yang tepat untuk melakukan apa yang Anda minta.

Jika Anda membutuhkan jenis sintaks itu, pertimbangkan beberapa Groovy, yang kompatibel dengan Java dan memungkinkan Anda melakukannya:

def map = [name:"Gromit", likes:"cheese", id:1234]
dfraser
sumber
6

Inilah kelas sederhana yang akan mencapai apa yang Anda inginkan

import java.util.HashMap;

public class QuickHash extends HashMap<String,String> {
    public QuickHash(String...KeyValuePairs) {
        super(KeyValuePairs.length/2);
        for(int i=0;i<KeyValuePairs.length;i+=2)
            put(KeyValuePairs[i], KeyValuePairs[i+1]);
    }
}

Dan kemudian menggunakannya

Map<String, String> Foo=QuickHash(
    "a", "1",
    "b", "2"
);

Ini hasil {a:1, b:2}

Dakusan
sumber
5
    boolean x;
    for (x = false, 
        map.put("One", new Integer(1)), 
        map.put("Two", new Integer(2)),      
        map.put("Three", new Integer(3)); x;);

Mengabaikan deklarasi x(yang diperlukan untuk menghindari diagnostik "unreachable statement"), secara teknis itu hanya satu pernyataan.

Licks panas
sumber
14
Ini menjijikkan.
Micah Stairs
1
@MicahStairs - Tapi itu hanya satu pernyataan.
Hot Licks
2
Benar, tapi ini adalah jenis kode yang saya tidak pernah berharap untuk menemukannya dalam produksi.
Micah Stairs
@MicahStairs - Saya telah melihat lebih buruk.
Hot Licks
1
Ya ampun, saya telah mencari hari ini, bagaimana kode ini bekerja? Saya telah menambahkannya ke dalam kode untuk pengujian tetapi saya tidak tahu cara kerjanya secara internal ... :)
GOXR3PLUS
1

Anda dapat menambahkan fungsi utilitas ini ke kelas utilitas:

public static <K, V> Map<K, V> mapOf(Object... keyValues) {
    Map<K, V> map = new HashMap<>();

    for (int index = 0; index < keyValues.length / 2; index++) {
        map.put((K)keyValues[index * 2], (V)keyValues[index * 2 + 1]);
    }

    return map;
}

Map<Integer, String> map1 = YourClass.mapOf(1, "value1", 2, "value2");
Map<String, String> map2 = YourClass.mapOf("key1", "value1", "key2", "value2");

Catatan: Java 9Anda dapat menggunakan Map.of

R. Oosterholt
sumber
Metode ini tidak boleh digunakan karena penerapannya bukan tipe aman! Contoh: Map <Integer, String> map1 = mapOf (1, "value1", "key", 2, 2L);
jul
Yah, saya berharap programmer yang menentukan Map<Integer, String>, juga menyediakan tipe-tipe itu ...
R. Oosterholt
-1

Pendekatan lain mungkin menulis fungsi khusus untuk mengekstrak semua nilai elemen dari satu string dengan ekspresi reguler:

import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Example {
    public static void main (String[] args){
        HashMap<String,Integer> hashMapStringInteger = createHashMapStringIntegerInOneStat("'one' => '1', 'two' => '2' , 'three'=>'3'  ");

        System.out.println(hashMapStringInteger); // {one=1, two=2, three=3}
    }

    private static HashMap<String, Integer> createHashMapStringIntegerInOneStat(String str) {
        HashMap<String, Integer> returnVar = new HashMap<String, Integer>();

        String currentStr = str;
        Pattern pattern1 = Pattern.compile("^\\s*'([^']*)'\\s*=\\s*>\\s*'([^']*)'\\s*,?\\s*(.*)$");

        // Parse all elements in the given string.
        boolean thereIsMore = true;
        while (thereIsMore){
            Matcher matcher = pattern1.matcher(currentStr);
            if (matcher.find()) {
                returnVar.put(matcher.group(1),Integer.valueOf(matcher.group(2)));
                currentStr = matcher.group(3);
            }
            else{
                thereIsMore = false;
            }
        }

        // Validate that all elements in the given string were parsed properly
        if (currentStr.length() > 0){
            System.out.println("WARNING: Problematic string format. given String: " + str);
        }

        return returnVar;
    }
}
Uri Ziv
sumber