dog*_*ane 1084 java collections dictionary initialization idiomatic
你会如何Map在Java中初始化静态?
方法一:静态初始化
方法二:实例初始化(匿名子类)还是其他一些方法?
各自的优点和缺点是什么?
这是一个说明两种方法的示例:
import java.util.HashMap;
import java.util.Map;
public class Test {
private static final Map<Integer, String> myMap = new HashMap<Integer, String>();
static {
myMap.put(1, "one");
myMap.put(2, "two");
}
private static final Map<Integer, String> myMap2 = new HashMap<Integer, String>(){
{
put(1, "one");
put(2, "two");
}
};
}
Run Code Online (Sandbox Code Playgroud)
Mis*_*ble 1074
在这种情况下,实例初始化器只是语法糖,对吧?我不明白为什么你需要一个额外的匿名类来初始化.如果正在创建的类是最终的,它将无法工作.
您也可以使用静态初始化器创建不可变映射:
public class Test {
private static final Map<Integer, String> myMap;
static {
Map<Integer, String> aMap = ....;
aMap.put(1, "one");
aMap.put(2, "two");
myMap = Collections.unmodifiableMap(aMap);
}
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*nik 428
我喜欢Guava初始化静态不可变映射的方法:
static final Map<Integer, String> MY_MAP = ImmutableMap.of(
1, "one",
2, "two"
);
Run Code Online (Sandbox Code Playgroud)
如您所见,它非常简洁(因为方便的工厂方法ImmutableMap).
如果您希望地图有超过5个条目,则无法再使用ImmutableMap.of().相反,尝试ImmutableMap.builder()以下这些方面:
static final Map<Integer, String> MY_MAP = ImmutableMap.<Integer, String>builder()
.put(1, "one")
.put(2, "two")
// ...
.put(15, "fifteen")
.build();
Run Code Online (Sandbox Code Playgroud)
要了解更多有关的番石榴的不可变集合实用工具的好处,看到解释不可改变的集合番石榴用户指南中.
(其中一部分)Guava曾被称为Google Collections.如果您尚未在Java项目中使用此库,我强烈建议您尝试使用它!正如SO用户所认同的那样,Guava已经迅速成为Java最受欢迎和最有用的免费第三方库之一.(如果您是新手,那么该链接背后有一些优秀的学习资源.)
更新(2015):至于Java 8,我仍然会使用Guava方法,因为它比其他任何方式更清洁.如果您不想要Guava依赖,请考虑一个普通的旧init方法.如果你问我,那么带有二维数组和Stream API的hack 非常难看,如果你需要创建一个键和值不是同一类型的Map(比如Map<Integer, String>问题),那么它会变得更加丑陋.
至于番石榴的未来,就Java 8而言,Louis Wasserman 早在2014 年就已经说过,并且在2016年[ 更新 ]宣布Guava 21将要求并正确支持Java 8.
更新(2016):正如Tagir Valeev所指出的那样,Java 9最终会通过为集合添加便利工厂方法来使用纯粹的JDK.
static final Map<Integer, String> MY_MAP = Map.of(
1, "one",
2, "two"
);
Run Code Online (Sandbox Code Playgroud)
Chr*_*Noe 176
Java 5提供了这种更紧凑的语法:
static final Map<String , String> FLAVORS = new HashMap<String , String>() {{
put("Up", "Down");
put("Charm", "Strange");
put("Top", "Bottom");
}};
Run Code Online (Sandbox Code Playgroud)
Pet*_*aný 173
我会用:
public class Test {
private static final Map<Integer, String> MY_MAP = createMap();
private static Map<Integer, String> createMap() {
Map<Integer, String> result = new HashMap<Integer, String>();
result.put(1, "one");
result.put(2, "two");
return Collections.unmodifiableMap(result);
}
}
Run Code Online (Sandbox Code Playgroud)
Out*_*mer 94
第二种方法的一个优点是你可以用它来包装,Collections.unmodifiableMap()以保证以后什么都不会更新集合:
private static final Map<Integer, String> CONSTANT_MAP =
Collections.unmodifiableMap(new HashMap<Integer, String>() {{
put(1, "one");
put(2, "two");
}});
// later on...
CONSTANT_MAP.put(3, "three"); // going to throw an exception!
Run Code Online (Sandbox Code Playgroud)
Luk*_*son 61
这是一个Java 8单行静态地图初始化器:
private static final Map<String, String> EXTENSION_TO_MIMETYPE =
Arrays.stream(new String[][] {
{ "txt", "text/plain" },
{ "html", "text/html" },
{ "js", "application/javascript" },
{ "css", "text/css" },
{ "xml", "application/xml" },
{ "png", "image/png" },
{ "gif", "image/gif" },
{ "jpg", "image/jpeg" },
{ "jpeg", "image/jpeg" },
{ "svg", "image/svg+xml" },
}).collect(Collectors.toMap(kv -> kv[0], kv -> kv[1]));
Run Code Online (Sandbox Code Playgroud)
编辑:要Map<Integer, String>在问题中初始化a ,你需要这样的东西:
static final Map<Integer, String> MY_MAP = Arrays.stream(new Object[][]{
{1, "one"},
{2, "two"},
}).collect(Collectors.toMap(kv -> (Integer) kv[0], kv -> (String) kv[1]));
Run Code Online (Sandbox Code Playgroud)
编辑(2):i_am_zero有一个更好的,具有混合类型功能的版本,它使用一组new SimpleEntry<>(k, v)调用.看看答案:https://stackoverflow.com/a/37384773/3950982
Tag*_*eev 50
在Java 9中:
private static final Map<Integer, String> MY_MAP = Map.of(1, "one", 2, "two");
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请参阅JEP 269.JDK 9 于2017年9月全面上市.
i_a*_*ero 37
我们可以Map.ofEntries用作:
import static java.util.Map.entry;
private static final Map<Integer,String> map = Map.ofEntries(
entry(1, "one"),
entry(2, "two"),
entry(3, "three"),
entry(4, "four"),
entry(5, "five"),
entry(6, "six"),
entry(7, "seven"),
entry(8, "eight"),
entry(9, "nine"),
entry(10, "ten"));
Run Code Online (Sandbox Code Playgroud)
我们也可以Map.of按照Tagir的建议使用他的答案,但我们不能使用超过10个条目Map.of.
我们可以创建一个地图条目流.我们已经有两个实现Entry在java.util.AbstractMap它们SimpleEntry和SimpleImmutableEntry.对于这个例子,我们可以使用前者:
import java.util.AbstractMap.*;
private static final Map<Integer, String> myMap = Stream.of(
new SimpleEntry<>(1, "one"),
new SimpleEntry<>(2, "two"),
new SimpleEntry<>(3, "three"),
new SimpleEntry<>(4, "four"),
new SimpleEntry<>(5, "five"),
new SimpleEntry<>(6, "six"),
new SimpleEntry<>(7, "seven"),
new SimpleEntry<>(8, "eight"),
new SimpleEntry<>(9, "nine"),
new SimpleEntry<>(10, "ten"))
.collect(Collectors.toMap(SimpleEntry::getKey, SimpleEntry::getValue));
Run Code Online (Sandbox Code Playgroud)
Don*_*aab 31
使用Eclipse Collections,以下所有方法都可以:
import java.util.Map;
import org.eclipse.collections.api.map.ImmutableMap;
import org.eclipse.collections.api.map.MutableMap;
import org.eclipse.collections.impl.factory.Maps;
public class StaticMapsTest
{
private static final Map<Integer, String> MAP =
Maps.mutable.with(1, "one", 2, "two");
private static final MutableMap<Integer, String> MUTABLE_MAP =
Maps.mutable.with(1, "one", 2, "two");
private static final MutableMap<Integer, String> UNMODIFIABLE_MAP =
Maps.mutable.with(1, "one", 2, "two").asUnmodifiable();
private static final MutableMap<Integer, String> SYNCHRONIZED_MAP =
Maps.mutable.with(1, "one", 2, "two").asSynchronized();
private static final ImmutableMap<Integer, String> IMMUTABLE_MAP =
Maps.mutable.with(1, "one", 2, "two").toImmutable();
private static final ImmutableMap<Integer, String> IMMUTABLE_MAP2 =
Maps.immutable.with(1, "one", 2, "two");
}
Run Code Online (Sandbox Code Playgroud)
您还可以使用Eclipse Collections静态初始化原始映射.
import org.eclipse.collections.api.map.primitive.ImmutableIntObjectMap;
import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
import org.eclipse.collections.impl.factory.primitive.IntObjectMaps;
public class StaticPrimitiveMapsTest
{
private static final MutableIntObjectMap<String> MUTABLE_INT_OBJ_MAP =
IntObjectMaps.mutable.<String>empty()
.withKeyValue(1, "one")
.withKeyValue(2, "two");
private static final MutableIntObjectMap<String> UNMODIFIABLE_INT_OBJ_MAP =
IntObjectMaps.mutable.<String>empty()
.withKeyValue(1, "one")
.withKeyValue(2, "two")
.asUnmodifiable();
private static final MutableIntObjectMap<String> SYNCHRONIZED_INT_OBJ_MAP =
IntObjectMaps.mutable.<String>empty()
.withKeyValue(1, "one")
.withKeyValue(2, "two")
.asSynchronized();
private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP =
IntObjectMaps.mutable.<String>empty()
.withKeyValue(1, "one")
.withKeyValue(2, "two")
.toImmutable();
private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP2 =
IntObjectMaps.immutable.<String>empty()
.newWithKeyValue(1, "one")
.newWithKeyValue(2, "two");
}
Run Code Online (Sandbox Code Playgroud)
注意:我是Eclipse Collections的提交者
elj*_*nso 28
在这种情况下,我永远不会创建一个匿名子类.如果您想使地图不可修改,静态初始化程序也可以正常工作:
private static final Map<Integer, String> MY_MAP;
static
{
Map<Integer, String>tempMap = new HashMap<Integer, String>();
tempMap.put(1, "one");
tempMap.put(2, "two");
MY_MAP = Collections.unmodifiableMap(tempMap);
}
Run Code Online (Sandbox Code Playgroud)
小智 17
我喜欢匿名类,因为它很容易处理它:
public static final Map<?, ?> numbers = Collections.unmodifiableMap(new HashMap<Integer, String>() {
{
put(1, "some value");
//rest of code here
}
});
Run Code Online (Sandbox Code Playgroud)
Len*_*oju 12
public class Test {
private static final Map<Integer, String> myMap;
static {
Map<Integer, String> aMap = ....;
aMap.put(1, "one");
aMap.put(2, "two");
myMap = Collections.unmodifiableMap(aMap);
}
}
Run Code Online (Sandbox Code Playgroud)
如果我们声明了多个常量,那么该代码将被编写为静态块,并且将来很难维护.所以最好使用匿名类.
public class Test {
public static final Map numbers = Collections.unmodifiableMap(new HashMap(2, 1.0f){
{
put(1, "one");
put(2, "two");
}
});
}
Run Code Online (Sandbox Code Playgroud)
并且建议使用不可修改的Map作为常量,否则它不能被视为常量.
Den*_*s C 10
我强烈建议静态块样式的"双支撑初始化"样式.
有人可能会评论他们不喜欢匿名类,开销,性能等.
但我更考虑的是代码的可读性和可维护性.在这一点上,我站在一个双支撑是一个更好的代码风格而不是静态方法.
另外,你知道匿名类的GC,你总是可以使用它将它转换为普通的HashMap new HashMap(Map map).
你可以这样做,直到你遇到另一个问题.如果这样做,您应该使用完整的另一种编码风格(例如,没有静态,工厂类).
像往常一样apache-commons有正确的方法MapUtils.putAll(Map,Object []):
例如,要创建颜色映射:
Map<String, String> colorMap = MapUtils.putAll(new HashMap<String, String>(), new String[][] {
{"RED", "#FF0000"},
{"GREEN", "#00FF00"},
{"BLUE", "#0000FF"}
});
Run Code Online (Sandbox Code Playgroud)
这是我最喜欢的,当我不想(或不能)使用番石榴ImmutableMap.of(),或者如果我需要一个可变的Map:
public static <A> Map<String, A> asMap(Object... keysAndValues) {
return new LinkedHashMap<String, A>() {{
for (int i = 0; i < keysAndValues.length - 1; i++) {
put(keysAndValues[i].toString(), (A) keysAndValues[++i]);
}
}};
}
Run Code Online (Sandbox Code Playgroud)
它非常紧凑,它忽略了杂散值(即没有值的最终键).
用法:
Map<String, String> one = asMap("1stKey", "1stVal", "2ndKey", "2ndVal");
Map<String, Object> two = asMap("1stKey", Boolean.TRUE, "2ndKey", new Integer(2));
Run Code Online (Sandbox Code Playgroud)
如果你想要不可修改的地图,最后java 9 of为Map界面添加了一个很酷的工厂方法.类似的方法也被添加到Set,List中.
Map<String, String> unmodifiableMap = Map.of("key1", "value1", "key2", "value2");
我更喜欢使用静态初始化程序来避免生成匿名类(没有其他目的),因此我将列出使用静态初始化程序初始化的技巧.所有列出的解决方案/提示都是类型安全的.
注意:这个问题并没有说明使地图不可修改的问题,所以我会把它留下来,但要知道它可以很容易地完成Collections.unmodifiableMap(map).
第一个提示
第一个提示是您可以对地图进行本地引用,并为其指定SHORT名称:
private static final Map<Integer, String> myMap = new HashMap<>();
static {
final Map<Integer, String> m = myMap; // Use short name!
m.put(1, "one"); // Here referencing the local variable which is also faster!
m.put(2, "two");
m.put(3, "three");
}
Run Code Online (Sandbox Code Playgroud)
第二个提示
第二个提示是您可以创建一个辅助方法来添加条目; 如果你想要,你也可以公开这个帮助方法:
private static final Map<Integer, String> myMap2 = new HashMap<>();
static {
p(1, "one"); // Calling the helper method.
p(2, "two");
p(3, "three");
}
private static void p(Integer k, String v) {
myMap2.put(k, v);
}
Run Code Online (Sandbox Code Playgroud)
这里的辅助方法不可重用,因为它只能添加元素myMap2.为了使它可以重用,我们可以使map本身成为helper方法的参数,但是初始化代码不会更短.
第三个提示
第三个提示是,您可以使用填充功能创建一个可重复使用的类似于构建器的帮助程序类.这是一个简单的10行助手类,它是类型安全的:
public class Test {
private static final Map<Integer, String> myMap3 = new HashMap<>();
static {
new B<>(myMap3) // Instantiating the helper class with our map
.p(1, "one")
.p(2, "two")
.p(3, "three");
}
}
class B<K, V> {
private final Map<K, V> m;
public B(Map<K, V> m) {
this.m = m;
}
public B<K, V> p(K k, V v) {
m.put(k, v);
return this; // Return this for chaining
}
}
Run Code Online (Sandbox Code Playgroud)
如果您想要简洁且相对安全的东西,则可以将编译时类型检查移至运行时:
static final Map<String, Integer> map = MapUtils.unmodifiableMap(
String.class, Integer.class,
"cat", 4,
"dog", 2,
"frog", 17
);
Run Code Online (Sandbox Code Playgroud)
此实现应捕获任何错误:
import java.util.HashMap;
public abstract class MapUtils
{
private MapUtils() { }
public static <K, V> HashMap<K, V> unmodifiableMap(
Class<? extends K> keyClazz,
Class<? extends V> valClazz,
Object...keyValues)
{
return Collections.<K, V>unmodifiableMap(makeMap(
keyClazz,
valClazz,
keyValues));
}
public static <K, V> HashMap<K, V> makeMap(
Class<? extends K> keyClazz,
Class<? extends V> valClazz,
Object...keyValues)
{
if (keyValues.length % 2 != 0)
{
throw new IllegalArgumentException(
"'keyValues' was formatted incorrectly! "
+ "(Expected an even length, but found '" + keyValues.length + "')");
}
HashMap<K, V> result = new HashMap<K, V>(keyValues.length / 2);
for (int i = 0; i < keyValues.length;)
{
K key = cast(keyClazz, keyValues[i], i);
++i;
V val = cast(valClazz, keyValues[i], i);
++i;
result.put(key, val);
}
return result;
}
private static <T> T cast(Class<? extends T> clazz, Object object, int i)
{
try
{
return clazz.cast(object);
}
catch (ClassCastException e)
{
String objectName = (i % 2 == 0) ? "Key" : "Value";
String format = "%s at index %d ('%s') wasn't assignable to type '%s'";
throw new IllegalArgumentException(String.format(format, objectName, i, object.toString(), clazz.getSimpleName()), e);
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
817772 次 |
| 最近记录: |