Guava bize Java türleri için harika fabrika yöntemleri sağlar Maps.newHashMap()
.
Peki java Haritaları için de kurucular var mı?
HashMap<String,Integer> m = Maps.BuildHashMap.
put("a",1).
put("b",2).
build();
Guava bize Java türleri için harika fabrika yöntemleri sağlar Maps.newHashMap()
.
Peki java Haritaları için de kurucular var mı?
HashMap<String,Integer> m = Maps.BuildHashMap.
put("a",1).
put("b",2).
build();
Yanıtlar:
Java 9 Map
arayü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:
null
s'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ş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") );
null
değerlere izin vermediğini ve bu durumun kullanım durumuna bağlı olarak sorun olabileceğini unutmayın.
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).
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());
ImmutableMap
null
değerleri desteklemiyor . Yani bu yaklaşımın sınırlama yoktur: Eğer değerleri ayarlayamıyor HashMap
To null
.
new HashMap
Java yapıcısı yerine statik Maps.newHashMap
yöntemi?
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");
}};
map instanceof HashMap
yanlış olmaz mı? O kadar da iyi olmayan bir fikir gibi görünüyor.
map.getClass()==HashMap.class
yanlış döndürür. Ama bu yine de aptalca bir sınav. HashMap.class.isInstance(map)
tercih edilmelidir ve bu doğru olacaktır.
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.
İş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
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());
}
}
}
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.
Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 2);
, daha iyi?
HashMap
değişebilir; bir inşaatçıya gerek yok.
Map<String, Integer> map = Maps.newHashMap();
map.put("a", 1);
map.put("b", 2);
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.
ImmutableMap
Tabii orada söylemeliydim .
{{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 null
da son durumda olduğundan, asla yarı dolu olmadığından emin olun.
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.
Bir süre önce benzer bir ihtiyacım vardı. Guava ile ilgisi yok ama Map
akı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")
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;
}
İş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();
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)
);
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}]}