Guava ให้วิธีการโรงงานที่ยอดเยี่ยมสำหรับประเภท Java แก่เราเช่นMaps.newHashMap()
.
แต่ยังมีผู้สร้างสำหรับแผนที่ java ด้วยหรือไม่?
HashMap<String,Integer> m = Maps.BuildHashMap.
put("a",1).
put("b",2).
build();
Guava ให้วิธีการโรงงานที่ยอดเยี่ยมสำหรับประเภท Java แก่เราเช่นMaps.newHashMap()
.
แต่ยังมีผู้สร้างสำหรับแผนที่ java ด้วยหรือไม่?
HashMap<String,Integer> m = Maps.BuildHashMap.
put("a",1).
put("b",2).
build();
คำตอบ:
เนื่องจากMap
อินเทอร์เฟซJava 9 ประกอบด้วย:
Map.of(k1,v1, k2,v2, ..)
Map.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2), ..)
. ข้อ จำกัด ของวิธีการโรงงานเหล่านั้นคือ:
null
s เป็นคีย์และ / หรือค่าได้ (หากคุณต้องการเก็บค่าว่างลองดูคำตอบอื่น ๆ )หากเราต้องการแผนที่ที่เปลี่ยนแปลงได้ (เช่น HashMap) เราสามารถใช้ตัวสร้างการคัดลอกและปล่อยให้มันคัดลอกเนื้อหาของแผนที่ที่สร้างผ่านMap.of(..)
Map<Integer, String> map = new HashMap<>( Map.of(1,"a", 2,"b", 3,"c") );
null
ค่าซึ่งอาจเป็นปัญหาได้ขึ้นอยู่กับกรณีการใช้งาน
Map.of(k1,v1, k2,v2, ...)
สามารถใช้ได้อย่างปลอดภัยเมื่อเราไม่มีค่ามากมาย สำหรับค่าจำนวนMap.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2), ...)
มากขึ้นทำให้เราสามารถอ่านโค้ดได้มากขึ้นซึ่งมีโอกาสเกิดข้อผิดพลาดน้อยกว่า (เว้นแต่ฉันเข้าใจคุณผิด)
ไม่มีสิ่งนี้สำหรับ HashMaps แต่คุณสามารถสร้าง ImmutableMap ด้วยตัวสร้าง:
final Map<String, Integer> m = ImmutableMap.<String, Integer>builder().
put("a", 1).
put("b", 2).
build();
และหากคุณต้องการแผนที่ที่เปลี่ยนแปลงได้คุณสามารถป้อนข้อมูลนั้นไปยังตัวสร้าง HashMap
final Map<String, Integer> m = Maps.newHashMap(
ImmutableMap.<String, Integer>builder().
put("a", 1).
put("b", 2).
build());
ImmutableMap
ไม่รองรับnull
ค่า ดังนั้นจึงมีข้อ จำกัด ของวิธีการนี้: คุณไม่สามารถตั้งค่าในของคุณจะHashMap
null
new HashMap
Java constructor แทนMaps.newHashMap
วิธีการแบบคงที่หรือไม่?
ไม่ใช่ตัวสร้าง แต่ใช้ตัวเริ่มต้น:
Map<String, String> map = new HashMap<String, String>() {{
put("a", "1");
put("b", "2");
}};
map instanceof HashMap
เป็นเท็จ? ดูเหมือนเป็นความคิดที่ไม่ค่อยดีนัก
map.getClass()==HashMap.class
จะกลับเท็จ แต่นั่นเป็นการทดสอบที่โง่อยู่แล้ว HashMap.class.isInstance(map)
ควรเป็นที่ต้องการและจะกลับมาเป็นจริง
สิ่งนี้คล้ายกับคำตอบที่ยอมรับ แต่ดูสะอาดกว่าเล็กน้อยในมุมมองของฉัน:
ImmutableMap.of("key1", val1, "key2", val2, "key3", val3);
วิธีการข้างต้นมีหลายรูปแบบและเหมาะสำหรับการสร้างแผนที่แบบคงที่ไม่เปลี่ยนแปลงไม่เปลี่ยนรูป
นี่คือสิ่งที่ง่ายมาก ...
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);
}
}
แล้ว
import static FluentHashMap.map;
HashMap<String, Integer> m = map("a", 1).with("b", 2);
ดูhttps://gist.github.com/culmat/a3bcc646fa4401641ac6eb01f3719065
เครื่องมือสร้างแผนที่ที่เรียบง่ายเป็นเรื่องเล็กน้อยที่จะเขียน:
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());
}
}
}
คุณสามารถใช้ได้:
HashMap<String,Integer> m = Maps.newHashMap(
ImmutableMap.of("a",1,"b",2)
);
มันไม่ดีงามและอ่านง่าย แต่ใช้งานได้จริง
Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 2);
, ดีกว่า?
HashMap
ไม่แน่นอน; ไม่จำเป็นต้องมีผู้สร้าง
Map<String, Integer> map = Maps.newHashMap();
map.put("a", 1);
map.put("b", 2);
ImmutableSet
ต้องการข้อมูลที่จะไม่เปลี่ยนรูปและควรใช้ หากคุณต้องการให้มันเปลี่ยนแปลงได้จริงๆคุณสามารถเริ่มต้นได้ในตัวสร้างหรือบล็อกตัวเริ่มต้นอินสแตนซ์หรือบล็อกตัวเริ่มต้นแบบคงที่หากเป็นฟิลด์แบบคงที่
ImmutableMap
ชัด ๆ
{{init();}}
(ไม่ใช่ในตัวสร้างเนื่องจากตัวสร้างอื่นอาจลืมมัน) และเป็นเรื่องดีที่เป็นการกระทำของอะตอม หากแผนที่มีความผันผวนให้ทำการกำหนดค่าเริ่มต้นด้วยตัวสร้างเพื่อให้แน่ใจว่าแผนที่นั้นเสมอnull
หรืออยู่ในสถานะสุดท้ายไม่ต้องเติมครึ่งหนึ่ง
คุณสามารถใช้ Fluent API ในEclipse Collections :
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);
นี่คือบล็อกที่มีรายละเอียดและตัวอย่างเพิ่มเติม
หมายเหตุ: ฉันเป็นผู้กำหนดค่า Eclipse Collections
ฉันมีความต้องการที่คล้ายกันในขณะที่กลับมา มันไม่เกี่ยวอะไรกับฝรั่ง แต่คุณสามารถทำอะไรแบบนี้เพื่อให้สามารถสร้างMap
โดยใช้เครื่องมือสร้างที่คล่องแคล่วได้อย่างหมดจด
สร้างคลาสพื้นฐานที่ขยายแผนที่
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;
}
}
จากนั้นสร้างเครื่องมือสร้างที่คล่องแคล่วด้วยวิธีการที่เหมาะกับความต้องการของคุณ:
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...
}
จากนั้นคุณสามารถใช้งานได้ดังนี้:
ValueMap map = new ValueMap()
.withValue("key 1", "value 1")
.withValue("key 2", "value 2")
.withValue("key 3", "value 3")
นี่คือสิ่งที่ฉันต้องการมาตลอดโดยเฉพาะอย่างยิ่งในขณะตั้งค่าการทดสอบ ในที่สุดฉันตัดสินใจที่จะเขียนโปรแกรมสร้างที่คล่องแคล่วง่าย ๆ ของฉันเองที่สามารถสร้างการใช้งานแผนที่ได้ - 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;
}
นี่คือสิ่งที่ฉันเขียน
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);
}
}
คุณใช้สิ่งนี้:
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:
นี่คือแนวทางของ Java-9 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);
}
}
วิธีใช้:
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)
);
มีImmutableMap.builder()
ในฝรั่ง
Underscore-javaสามารถสร้าง hashmap
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}]}