如何初始化静态地图?
如何在 Java 中初始化静态 Map
?
方法一:静态初始化
方法二:实例初始化(匿名子类)
或者
还有其他方法吗?
各自的优点和缺点是什么?
这是说明这两种方法的示例:
import java.util.HashMap;
import java.util.Map;
public class Test {
private static final Map<Integer, String> myMap = new HashMap<>();
static {
myMap.put(1, "one");
myMap.put(2, "two");
}
private static final Map<Integer, String> myMap2 = new HashMap<>(){
{
put(1, "one");
put(2, "two");
}
};
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
在这种情况下,实例初始化程序只是语法糖,对吧? 我不明白为什么你需要一个额外的匿名类来初始化。 如果正在创建的类是最终类,则它将不起作用。
您也可以使用静态初始化程序创建不可变映射:
The instance initialiser is just syntactic sugar in this case, right? I don't see why you need an extra anonymous class just to initialize. And it won't work if the class being created is final.
You can create an immutable map using a static initialiser too:
我喜欢 Guava 初始化静态、不可变映射的方式:
如您所见,它非常简洁(因为< 中方便的工厂方法代码>ImmutableMap)。
如果您希望映射有超过 5 个条目,则不能再使用
ImmutableMap.of()
。 相反,请尝试ImmutableMap.builder()
大致思路如下:要了解有关 Guava 不可变集合实用程序的优势的更多信息,请参阅 Guava 用户指南中的不可变集合解释。
Guava(Guava 的一个子集)曾经被称为Google Collections。 如果您尚未在 Java 项目中使用此库,我强烈建议尝试一下! Guava 已迅速成为 Java 中最受欢迎和最有用的免费第 3 方库之一,如 SO用户同意。 (如果您是新手,该链接后面有一些优秀的学习资源。)
更新(2015):至于Java 8,嗯,我仍然会使用番石榴之所以采用,是因为它比其他任何东西都干净得多。 如果您不希望 Guava 依赖,请考虑使用普通的旧初始化方法。 如果你问我的话,二维数组和 Stream API 的破解是相当丑陋的,如果你需要创建的话,会变得更丑陋其键和值不是同一类型的 Map(如问题中的 Map)。
至于 Guava 的未来,关于 Java 8,Louis Wasserman 早在 2014 年就说过,并在 2016 年[更新]宣布Guava 21 将需要并正确支持 Java 8。
更新(2016):如塔吉尔Valeev 指出,Java 9 最终将通过添加 集合的便捷工厂方法:
I like the Guava way of initialising a static, immutable map:
As you can see, it's very concise (because of the convenient factory methods in
ImmutableMap
).If you want the map to have more than 5 entries, you can no longer use
ImmutableMap.of()
. Instead, tryImmutableMap.builder()
along these lines:To learn more about the benefits of Guava's immutable collection utilities, see Immutable Collections Explained in Guava User Guide.
(A subset of) Guava used to be called Google Collections. If you aren't using this library in your Java project yet, I strongly recommend trying it out! Guava has quickly become one of the most popular and useful free 3rd party libs for Java, as fellow SO users agree. (If you are new to it, there are some excellent learning resources behind that link.)
Update (2015): As for Java 8, well, I would still use the Guava approach because it is way cleaner than anything else. If you don't want Guava dependency, consider a plain old init method. The hack with two-dimensional array and Stream API is pretty ugly if you ask me, and gets uglier if you need to create a Map whose keys and values are not the same type (like
Map<Integer, String>
in the question).As for future of Guava in general, with regards to Java 8, Louis Wasserman said this back in 2014, and [update] in 2016 it was announced that Guava 21 will require and properly support Java 8.
Update (2016): As Tagir Valeev points out, Java 9 will finally make this clean to do using nothing but pure JDK, by adding convenience factory methods for collections:
我会使用:
I would use:
Java 5 提供了这种更紧凑的语法:
Java 5 provides this more compact syntax:
第二种方法的一个优点是,您可以用 Collections.unmodifyingMap() 包装它,以保证以后不会有任何内容更新集合:
One advantage to the second method is that you can wrap it with
Collections.unmodifiableMap()
to guarantee that nothing is going to update the collection later:Java 9+ 中的
Map.of
有关详细信息,请参阅 JEP 269。 JDK 9 于 2017 年 9 月正式发布。
Map.of
in Java 9+See JEP 269 for details. JDK 9 reached general availability in September 2017.
这是一个 Java 8 单行静态映射初始值设定项:
编辑:要像问题中那样初始化
Map
,您需要这样的内容:编辑(2):有一个i_am_zero 提供的更好的混合类型版本,它使用
new SimpleEntry<>(k, v)
调用流。 查看该答案:https://stackoverflow.com/a/37384773/3950982Here's a Java 8 one-line static map initializer:
Edit: to initialize a
Map<Integer, String>
as in the question, you'd need something like this:Edit(2): There is a better, mixed-type-capable version by i_am_zero that uses a stream of
new SimpleEntry<>(k, v)
calls. Check out that answer: https://stackoverflow.com/a/37384773/3950982Java 9
我们可以使用
Map.ofEntries
,调用Map.entry( k , v )
创建每个条目。我们还可以按照 Tagir 在他的回答这里中的建议使用
Map.of
,但我们不能使用Map.of
的条目超过 10 个。Java 8
我们可以创建映射条目流。 我们已经在
java.util.AbstractMap
中有两个Entry
实现,它们是 SimpleEntry 和 SimpleImmutableEntry。 对于这个例子,我们可以使用前者作为:Java 9
We can use
Map.ofEntries
, callingMap.entry( k , v )
to create each entry.We can also use
Map.of
as suggested by Tagir in his answer here but we cannot have more than 10 entries usingMap.of
.Java 8
We can create a Stream of map entries. We already have two implementations of
Entry
injava.util.AbstractMap
which are SimpleEntry and SimpleImmutableEntry. For this example we can make use of former as:使用 Eclipse Collections,以下所有功能都将起作用:
您还可以使用 Eclipse 静态初始化原始映射收藏。
注意:我是 Eclipse Collections 的提交者
With Eclipse Collections, all of the following will work:
You can also statically initialize primitive maps with Eclipse Collections.
Note: I am a committer for Eclipse Collections
在这种情况下我永远不会创建匿名子类。 如果您想让映射不可修改,静态初始值设定项同样可以很好地工作,例如:
I would never create an anonymous subclass in this situation. Static initializers work equally well, if you would like to make the map unmodifiable for example:
我喜欢匿名类,因为它很容易处理:
I like anonymous class, because it is easy to deal with it:
也许查看 Google 收藏会很有趣,例如他们页面上的视频。 它们提供了各种初始化映射和集合的方法,并提供不可变的集合。
更新:该库现已命名为 Guava。
Maybe it's interesting to check out Google Collections, e.g. the videos that they have on their page. They provide various ways to initialize maps and sets, and provide immutable collections as well.
Update: This library is now named Guava.
如果我们声明多个常量,那么该代码将被编写在静态块中,这在将来很难维护。 所以最好使用匿名类。
建议对常量使用 unmodificableMap,否则不能将其视为常量。
If we declare more than one constant then that code will be written in static block and that is hard to maintain in future. So it is better to use anonymous class.
And it is suggested to used unmodifiableMap for constants other wise it can't be treated as constant.
我强烈建议使用“双括号初始化”样式而不是静态块样式。
也许有人会说不喜欢匿名类、不喜欢开销、不喜欢性能等,
但我更考虑的是代码的可读性和可维护性。 从这个角度来看,我认为双括号是比静态方法更好的代码风格。
另外,如果您知道匿名类的GC,您始终可以使用
new HashMap(Map map)
将其转换为普通的HashMap。您可以这样做,直到遇到另一个问题为止。 如果这样做,您应该使用另一种编码风格(例如,无静态、工厂类)。
I could strongly suggest the "double brace initialization" style over static block style.
Someone may comment that they don't like anonymous class, overhead, performance, etc.
But that I more consider is the code readability and maintainability. In this point of view, I stand a double brace is a better code style rather then static method.
In addition, it you aware the GC of the anonymous class, you can always convert it to a normal HashMap by using
new HashMap(Map map)
.You can do this until you faced another problem. If you do, you should use complete another coding style (e.g. no static, factory class) for it.
像往常一样 apache-commons 有正确的方法 MapUtils.putAll(Map, Object[]):
例如,创建彩色图:
As usual apache-commons has proper method MapUtils.putAll(Map, Object[]):
For example, to create a color map:
如果我
ImmutableMap.of()
Map
Map.of()
非常紧凑,并且它忽略杂散值(即没有值的最终键)。
用法:
Here's my favorite if I
ImmutableMap.of()
Map
Map.of()
from JDK9+It's very compact, and it ignores stray values (i.e. a final key without a value).
Usage:
我更喜欢使用静态初始值设定项来避免生成匿名类(这将没有进一步的目的),因此我将列出使用静态初始值设定项进行初始化的提示。 所有列出的解决方案/提示都是类型安全的。
注意:这个问题没有提到任何关于使地图不可修改的内容,所以我将省略它,但知道它可以使用
Collections.unmodifyingMap(map)
。第一个技巧
第一个技巧是您可以对地图进行本地引用并为其指定一个简短名称:
第二个技巧
第二个技巧是您可以创建一个助手添加条目的方法; 如果您愿意,也可以将此辅助方法公开:
不过,此处的辅助方法不可重复使用,因为它只能向
myMap2
添加元素。 为了使其可重用,我们可以将映射本身作为辅助方法的参数,但初始化代码不会更短。第三个技巧
第三个技巧是您可以创建一个具有填充功能的可重用的类似构建器的帮助器类。 这实际上是一个简单的 10 行帮助器类,它是类型安全的:
I prefer using a static initializer to avoid generating anonymous classes (which would have no further purpose), so I'll list tips initializing with a static initializer. All listed solutions / tips are type-safe.
Note: The question doesn't say anything about making the map unmodifiable, so I will leave that out, but know that it can easily be done with
Collections.unmodifiableMap(map)
.First tip
The 1st tip is that you can make a local reference to the map and you give it a SHORT name:
Second tip
The 2nd tip is that you can create a helper method to add entries; you can also make this helper method public if you want to:
The helper method here is not re-usable though because it can only add elements to
myMap2
. To make it re-usable, we could make the map itself a parameter of the helper method, but then initialization code would not be any shorter.Third tip
The 3rd tip is that you can create a re-usable builder-like helper class with the populating functionality. This is really a simple, 10-line helper class which is type-safe:
如果你想要不可修改的地图,最后java 9在
Map
接口中添加了一个很酷的工厂方法of
。 Set、List也添加了类似的方法。地图<字符串,字符串> unmodifierMap = Map.of("key1", "value1", "key2", "value2");
If you want unmodifiable map, finally java 9 added a cool factory method
of
toMap
interface. Similar method is added to Set, List as well.Map<String, String> unmodifiableMap = Map.of("key1", "value1", "key2", "value2");
您创建的匿名类效果很好。 但是您应该知道这是一个内部类,因此它将包含对周围类实例的引用。 所以你会发现你不能用它做某些事情(使用 XStream 就是其中之一)。 你会得到一些非常奇怪的错误。
话虽如此,只要您意识到,这种方法就可以了。 我大部分时间都用它来以简洁的方式初始化各种集合。
编辑:在注释中正确指出这是一个静态类。 显然我没有仔细阅读这篇文章。 然而,我的评论do仍然适用于匿名内部类。
The anonymous class you're creating works well. However you should be aware that this is an inner class and as such, it'll contain a reference to the surrounding class instance. So you'll find you can't do certain things with it (using XStream for one). You'll get some very strange errors.
Having said that, so long as you're aware then this approach is fine. I use it most of the time for initialising all sorts of collections in a concise fashion.
EDIT: Pointed out correctly in the comments that this is a static class. Obviously I didn't read this closely enough. However my comments do still apply to anonymous inner classes.
如果您想要简洁且相对安全的东西,您可以将编译时类型检查转移到运行时:
此实现应该捕获任何错误:
If you want something terse and relatively safe, you can just shift compile-time type checking to run-time:
This implementation should catch any errors:
对于 Java 8,我开始使用以下模式:
它不是最简洁且有点迂回的模式,但
java.util
之外的任何内容,With Java 8 I've come to use the following pattern:
It's not the most terse and a bit roundabout, but
java.util
如果您只需要向映射添加一个值,可以使用 Collections.singletonMap:
If you only need to add one value to the map you can use Collections.singletonMap:
您可以使用
StickyMap
和MapEntry
来自 Cactoos:You may use
StickyMap
andMapEntry
from Cactoos:您的第二种方法(双括号初始化)被认为是反模式,所以我会采用第一种方法。
初始化静态 Map 的另一种简单方法是使用此实用程序函数:
注意:在 Java 9 中,您可以使用 Map.of
Your second approach (Double Brace initialization) is thought to be an anti pattern, so I would go for the first approach.
Another easy way to initialise a static Map is by using this utility function:
Note: in
Java 9
you can use Map.of我不喜欢静态初始化语法,也不相信匿名子类。 一般来说,我同意前面的答案中提到的使用静态初始值设定项的所有缺点以及使用匿名子类的所有缺点。 另一方面 - 这些帖子中介绍的优点对我来说还不够。 我更喜欢使用静态初始化方法:
I do not like Static initializer syntax and I'm not convinced to anonymous subclasses. Generally, I agree with all cons of using Static initializers and all cons of using anonymous subclasses that were mentioned in previus answers. On the other hand - pros presented in these posts are not enough for me. I prefer to use static initialization method:
我还没有看到我在任何答案中使用的方法(并且已经变得喜欢),所以这里是:
我不喜欢使用静态初始化器,因为它们很笨重,
我不喜欢匿名类,因为它为每个实例创建一个新类。
相反,我更喜欢如下所示的初始化:
不幸的是,这些方法不是标准 Java 库的一部分,
因此您需要创建(或使用)一个定义以下方法的实用程序库:(
您可以使用“导入静态”来避免需要在方法名称前添加前缀)
我发现为其他集合提供类似的静态方法很有用( list、set、sortedSet、sortedMap 等)
它不如 json 对象初始化那么好,但就可读性而言,它是朝这个方向迈出的一步。
I have not seen the approach I use (and have grown to like) posted in any answers, so here it is:
I don't like using static initializers because they are clunky,
and I don't like anonymous classes because it is creating a new class for each instance.
instead, I prefer initialization that looks like this:
unfortunately, these methods are not part of the standard Java library,
so you will need to create (or use) a utility library that defines the following methods:
(you can use 'import static' to avoid needing to prefix the method's name)
I found it useful to provide similar static methods for the other collections (list, set, sortedSet, sortedMap, etc.)
Its not quite as nice as json object initialization, but it's a step in that direction, as far as readability is concerned.
由于 Java 不支持映射文字,因此必须始终显式实例化和填充映射实例。
幸运的是,可以使用工厂方法来模拟 Java 中映射文字的行为。
例如:
输出:
这比一次创建并填充地图一个元素要方便得多。
Because Java does not support map literals, map instances must always be explicitly instantiated and populated.
Fortunately, it is possible to approximate the behavior of map literals in Java using factory methods.
For example:
Output:
It is a lot more convenient than creating and populating the map an element at a time.
JEP 269 为 Collections API 提供了一些便捷的工厂方法。 该工厂方法不在当前的 Java 版本(即 8)中,但计划在 Java 9 版本中使用。
对于
Map
有两个工厂方法:of
和ofEntries
。 使用of
,您可以传递交替的键/值对。 例如,为了创建像{age: 27, Major: cs}
这样的Map
:目前
of
有十个重载版本,因此您可以创建一个包含十个键/值对的映射。 如果您不喜欢这种限制或交替键/值,可以使用ofEntries
:of
和ofEntries
都将返回不可变的Map
,因此构建后您无法更改其元素。 您可以使用JDK 9 Early Access来尝试这些功能。JEP 269 provides some convenience factory methods for Collections API. This factory methods are not in current Java version, which is 8, but are planned for Java 9 release.
For
Map
there are two factory methods:of
andofEntries
. Usingof
, you can pass alternating key/value pairs. For example, in order to create aMap
like{age: 27, major: cs}
:Currently there are ten overloaded versions for
of
, so you can create a map containing ten key/value pairs. If you don't like this limitation or alternating key/values, you can useofEntries
:Both
of
andofEntries
will return an immutableMap
, so you can't change their elements after construction. You can try out these features using JDK 9 Early Access.嗯...我喜欢枚举;)
Well... I like enums ;)
我已经阅读了答案,并决定编写自己的地图生成器。 随意复制粘贴并享受。
编辑:最近,我经常发现公共静态方法
of
,而且我有点喜欢它。 我将其添加到代码中并将构造函数设为私有,从而切换到静态工厂方法模式。EDIT2:最近,我不再喜欢名为
of
的静态方法,因为使用静态导入时它看起来很糟糕。 我将其重命名为mapOf
,使其更适合静态导入。I've read the answers and i decided to write my own map builder. Feel free to copy-paste and enjoy.
EDIT: Lately, I keep finding public static method
of
pretty often and I kinda like it. I added it into the code and made the constructor private, thus switching to static factory method pattern.EDIT2: Even more recently, I no longer like static method called
of
, as it looks pretty bad when using static imports. I renamed it tomapOf
instead, making it more suitable for static imports.