HashMap için oluşturucu


Yanıtlar:


20

Java 9 Maparayüzü şunları içerdiğinden:

  • Map.of(k1,v1, k2,v2, ..)
  • Map.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2), ..).

Bu fabrika yöntemlerinin sınırlamaları şunlardır:

  • nulls'yi anahtarlar ve / veya değerler olarak tutamaz (boş değerleri saklamanız gerekiyorsa diğer yanıtlara bir göz atın)
  • değişmez haritalar üretmek

Değişken haritaya (HashMap gibi) ihtiyacımız varsa , onun copy-constructor'ını kullanabilir ve aracılığıyla oluşturulan haritanın içeriğiniMap.of(..)

Map<Integer, String> map = new HashMap<>( Map.of(1,"a", 2,"b", 3,"c") );

2
Java 9 yöntemlerinin nulldeğerlere izin vermediğini ve bu durumun kullanım durumuna bağlı olarak sorun olabileceğini unutmayın.
Başına Lundberg

@JoshM. Map.of(k1,v1, k2,v2, ...)Çok fazla değerimiz olmadığında IMO güvenle kullanılabilir. Daha büyük miktarda değerler Map.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2), ...)bize daha okunabilir kod verir ve bu da hataya daha az meyillidir (sizi yanlış anlamadıysam).
Pshemo

İyi anladın. İlki benim için gerçekten iğrenç; Kullanmayı reddediyorum!
Josh M.

164

HashMaps için böyle bir şey yoktur, ancak bir oluşturucu ile bir ImmutableMap oluşturabilirsiniz:

final Map<String, Integer> m = ImmutableMap.<String, Integer>builder().
      put("a", 1).
      put("b", 2).
      build();

Ve değiştirilebilir bir haritaya ihtiyacınız varsa, bunu HashMap yapıcısına besleyebilirsiniz.

final Map<String, Integer> m = Maps.newHashMap(
    ImmutableMap.<String, Integer>builder().
        put("a", 1).
        put("b", 2).
        build());

43
ImmutableMapnulldeğerleri desteklemiyor . Yani bu yaklaşımın sınırlama yoktur: Eğer değerleri ayarlayamıyor HashMapTo null.
vitaly

5
sean-patrick-floyd Pratik bir örnek: Spring'in NamedParameterJdbcTemplate'i , parametre adları ile anahtarlanmış değerlerin eşlemesini bekliyor. Diyelim ki bir sütun değerini null olarak ayarlamak için NamedParameterJdbcTemplate kullanmak istiyorum. Görmüyorum: a) nasıl bir kod kokusu olduğunu; b) burada boş nesne kalıbı nasıl kullanılır
vitaly

2
@vitaly buna karşı çıkamaz
Sean Patrick Floyd

2
Kullanarak orada bir şey yanlış mı new HashMapJava yapıcısı yerine statik Maps.newHashMapyöntemi?
CorayThan

1
@CorayThan - Jonik haklı, sadece statik tip çıkarımına dayanan bir kısayol. stackoverflow.com/a/13153812
AndersDJohnson

46

Tam olarak bir oluşturucu değil, ancak bir başlatıcı kullanarak:

Map<String, String> map = new HashMap<String, String>() {{
    put("a", "1");
    put("b", "2");
}};

Bekle. Bu map instanceof HashMapyanlış olmaz mı? O kadar da iyi olmayan bir fikir gibi görünüyor.
Elazar Leibovich

3
@Elazar map.getClass()==HashMap.classyanlış döndürür. Ama bu yine de aptalca bir sınav. HashMap.class.isInstance(map)tercih edilmelidir ve bu doğru olacaktır.
Sean Patrick Floyd

59
Dedi ki: Hala bu çözümün kötü olduğunu düşünüyorum.
Sean Patrick Floyd

11
Bu bir örnek başlatıcıdır, statik bir başlatıcı değildir. Sınıftaki her kurucu için üst yapıcının yapıcısından sonra, ancak yapıcının gövdesinden önce çalıştırılır. Yaşam döngüsü çok iyi bilinmediğinden bu deyimden kaçınıyorum.
Joe Coder

14
Bu çok kötü bir çözüm ve kaçınılması gereken: stackoverflow.com/a/27521360/3253277
Alexandre DuBreuil

36

Bu, kabul edilen cevaba benzer, ancak bana göre biraz daha temiz:

ImmutableMap.of("key1", val1, "key2", val2, "key3", val3);

Yukarıdaki yöntemin birkaç çeşidi vardır ve bunlar statik, değişmeyen, değişmez haritalar oluşturmak için harikadır.


4
Bir inşaatçı istedim. Bir avuç öğeyle sınırlısınız.
Elazar Leibovich

Güzel ve temiz, ama Perl'in => operatörünü özlememe neden oluyor ... bu tuhaf bir duygu.
Aaron Maenpaa

10

İşte çok basit bir tane ...

public class FluentHashMap<K, V> extends java.util.HashMap<K, V> {
  public FluentHashMap<K, V> with(K key, V value) {
    put(key, value);
    return this;
  }

  public static <K, V> FluentHashMap<K, V> map(K key, V value) {
    return new FluentHashMap<K, V>().with(key, value);
  }
}

sonra

import static FluentHashMap.map;

HashMap<String, Integer> m = map("a", 1).with("b", 2);

Bkz. Https://gist.github.com/culmat/a3bcc646fa4401641ac6eb01f3719065


Yaklaşımınızın sadeliğini beğendim. Özellikle 2017 olduğu için (şimdi neredeyse 2018!) Ve
JDK'da

Gerçekten harika görünüyor, teşekkürler. @MiladNaseri JDK'nın API'sinde hala böyle bir şeye sahip olmaması delilik, ne kadar utanç verici.
olasılık dışı

9

Basit bir harita oluşturucu yazmak önemsizdir:

public class Maps {

    public static <Q,W> MapWrapper<Q,W> map(Q q, W w) {
        return new MapWrapper<Q, W>(q, w);
    }

    public static final class MapWrapper<Q,W> {
        private final HashMap<Q,W> map;
        public MapWrapper(Q q, W w) {
            map = new HashMap<Q, W>();
            map.put(q, w);
        }
        public MapWrapper<Q,W> map(Q q, W w) {
            map.put(q, w);
            return this;
        }
        public Map<Q,W> getMap() {
            return map;
        }
    }

    public static void main(String[] args) {
        Map<String, Integer> map = Maps.map("one", 1).map("two", 2).map("three", 3).getMap();
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
    }
}

6

Kullanabilirsiniz:

HashMap<String,Integer> m = Maps.newHashMap(
    ImmutableMap.of("a",1,"b",2)
);

O kadar şık ve okunaklı değil, ama işe yarıyor.


1
Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 2);, daha iyi?
lschin

Oluşturucu ile aynı, ancak aşırı yüklerle uygulandığı için sınırlı miktarda veri var. Yalnızca birkaç öğeniz varsa - sanırım tercih edilir.
Elazar Leibovich

4

HashMapdeğişebilir; bir inşaatçıya gerek yok.

Map<String, Integer> map = Maps.newHashMap();
map.put("a", 1);
map.put("b", 2);

Ya onunla bir alanı başlatmak isterseniz? Aynı satırdaki tüm mantık, alan ve c'tor arasında dağılmış mantıktan daha iyidir.
Elazar Leibovich

@Elazar: Derleme zamanında bunun gibi bilinen belirli değerlerle bir alanı başlatmak istiyorsanız, genellikle o alanın değişmez olmasını istersiniz ve kullanmalısınız ImmutableSet. Gerçekten değişken olmasını istiyorsanız, bunu yapıcıda veya bir örnek başlatıcı bloğunda veya statik bir alansa bir statik başlatıcı bloğunda başlatabilirsiniz.
ColinD

1
ImmutableMapTabii orada söylemeliydim .
ColinD

Ben öyle düşünmüyorum. Aynı tanım satırında ilkleştirmeyi görmeyi, sonra onları statik olmayan bir ilkleştirmeye sıkıştırmayı tercih ederim {{init();}}(diğer kurucu bunu unutabileceği için kurucuda değil). Ve bir çeşit atomik hareket olması güzel. Harita uçucuysa, onu bir inşaatçı ile ilk kullanıma hazırlamak, her zaman ya nullda son durumda olduğundan, asla yarı dolu olmadığından emin olun.
Elazar Leibovich

1

Eclipse Koleksiyonlarında akıcı API'yi kullanabilirsiniz :

Map<String, Integer> map = Maps.mutable.<String, Integer>empty()
        .withKeyValue("a", 1)
        .withKeyValue("b", 2);

Assert.assertEquals(Maps.mutable.with("a", 1, "b", 2), map);

İşte daha fazla ayrıntı ve örnek içeren bir blog .

Not: Eclipse Koleksiyonlarının sorumlusuyum.


0

Bir süre önce benzer bir ihtiyacım vardı. Guava ile ilgisi yok ama Mapakıcı bir inşaatçı kullanarak temiz bir şekilde inşa edebilmek için böyle bir şey yapabilirsiniz .

Haritayı genişleten bir temel sınıf oluşturun.

public class FluentHashMap<K, V> extends LinkedHashMap<K, V> {
    private static final long serialVersionUID = 4857340227048063855L;

    public FluentHashMap() {}

    public FluentHashMap<K, V> delete(Object key) {
        this.remove(key);
        return this;
    }
}

Ardından, ihtiyaçlarınıza uygun yöntemlerle akıcı oluşturucuyu oluşturun:

public class ValueMap extends FluentHashMap<String, Object> {
    private static final long serialVersionUID = 1L;

    public ValueMap() {}

    public ValueMap withValue(String key, String val) {
        super.put(key, val);
        return this;
    }

... Add withXYZ to suit...

}

Daha sonra bunu şu şekilde uygulayabilirsiniz:

ValueMap map = new ValueMap()
      .withValue("key 1", "value 1")
      .withValue("key 2", "value 2")
      .withValue("key 3", "value 3")

0

Bu, özellikle test armatürleri kurarken her zaman istediğim bir şeydi. Son olarak, herhangi bir Harita uygulamasını oluşturabilecek basit bir akıcı oluşturucu yazmaya karar verdim - https://gist.github.com/samshu/b471f5a2925fa9d9b718795d8bbdfe42#file-mapbuilder-java

    /**
     * @param mapClass Any {@link Map} implementation type. e.g., HashMap.class
     */
    public static <K, V> MapBuilder<K, V> builder(@SuppressWarnings("rawtypes") Class<? extends Map> mapClass)
            throws InstantiationException,
            IllegalAccessException {
        return new MapBuilder<K, V>(mapClass);
    }

    public MapBuilder<K, V> put(K key, V value) {
        map.put(key, value);
        return this;
    }

    public Map<K, V> build() {
        return map;
    }

0

İşte yazdığım biri

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

public class MapBuilder<K, V> {

    private final Map<K, V> map;

    /**
     * Create a HashMap builder
     */
    public MapBuilder() {
        map = new HashMap<>();
    }

    /**
     * Create a HashMap builder
     * @param initialCapacity
     */
    public MapBuilder(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }

    /**
     * Create a Map builder
     * @param mapFactory
     */
    public MapBuilder(Supplier<Map<K, V>> mapFactory) {
        map = mapFactory.get();
    }

    public MapBuilder<K, V> put(K key, V value) {
        map.put(key, value);
        return this;
    }

    public Map<K, V> build() {
        return map;
    }

    /**
     * Returns an unmodifiable Map. Strictly speaking, the Map is not immutable because any code with a reference to
     * the builder could mutate it.
     *
     * @return
     */
    public Map<K, V> buildUnmodifiable() {
        return Collections.unmodifiableMap(map);
    }
}

Bunu şu şekilde kullanırsın:

Map<String, Object> map = new MapBuilder<String, Object>(LinkedHashMap::new)
    .put("event_type", newEvent.getType())
    .put("app_package_name", newEvent.getPackageName())
    .put("activity", newEvent.getActivity())
    .build();

0

Java 8'i kullanma:

Bu bir Java-9 yaklaşımıdır Map.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2), ...)

public class MapUtil {
    import static java.util.stream.Collectors.toMap;

    import java.util.AbstractMap.SimpleEntry;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.stream.Stream;

    private MapUtil() {}

    @SafeVarargs
    public static Map<String, Object> ofEntries(SimpleEntry<String, Object>... values) {
        return Stream.of(values).collect(toMap(Entry::getKey, Entry::getValue));
    }

    public static SimpleEntry<String, Object> entry(String key, Object value) {
        return new SimpleEntry<String, Object>(key, value);
    }
}

Nasıl kullanılır:

import static your.package.name.MapUtil.*;

import java.util.Map;

Map<String, Object> map = ofEntries(
        entry("id", 1),
        entry("description", "xyz"),
        entry("value", 1.05),
        entry("enable", true)
    );


0

Alt çizgi-java hashmap oluşturabilir.

Map<String, Object> value = U.objectBuilder()
        .add("firstName", "John")
        .add("lastName", "Smith")
        .add("age", 25)
        .add("address", U.arrayBuilder()
            .add(U.objectBuilder()
                .add("streetAddress", "21 2nd Street")
                .add("city", "New York")
                .add("state", "NY")
                .add("postalCode", "10021")))
        .add("phoneNumber", U.arrayBuilder()
            .add(U.objectBuilder()
                .add("type", "home")
                .add("number", "212 555-1234"))
            .add(U.objectBuilder()
                .add("type", "fax")
                .add("number", "646 555-4567")))
        .build();
    // {firstName=John, lastName=Smith, age=25, address=[{streetAddress=21 2nd Street,
    // city=New York, state=NY, postalCode=10021}], phoneNumber=[{type=home, number=212 555-1234},
    // {type=fax, number=646 555-4567}]}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.