How to directly initialize a HashMap (in a literal way)?
All Versions
In case you happen to need just a single entry: There is Collections.singletonMap("key", "value")
.
For Java Version 9 or higher:
Yes, this is possible now. In Java 9 a couple of factory methods have been added that simplify the creation of maps :
// this works for up to 10 elements:
Map<String, String> test1 = Map.of(
"a", "b",
"c", "d"
);
// this works for any number of elements:
import static java.util.Map.entry;
Map<String, String> test2 = Map.ofEntries(
entry("a", "b"),
entry("c", "d")
);
In the example above both test
and test2
will be the same, just with different ways of expressing the Map. The Map.of
method is defined for up to ten elements in the map, while the Map.ofEntries
method will have no such limit.
Note that in this case the resulting map will be an immutable map. If you want the map to be mutable, you could copy it again, e.g. using mutableMap = new HashMap<>(Map.of("a", "b"));
(See also JEP 269 and the Javadoc)
For up to Java Version 8:
No, you will have to add all the elements manually. You can use an initializer in an anonymous subclass to make the syntax a little bit shorter:
Map<String, String> myMap = new HashMap<String, String>() {{
put("a", "b");
put("c", "d");
}};
However, the anonymous subclass might introduce unwanted behavior in some cases. This includes for example:
- It generates an additional class which increases memory consumption, disk space consumption and startup-time
- In case of a non-static method: It holds a reference to the object the creating method was called upon. That means the object of the outer class cannot be garbage collected while the created map object is still referenced, thus blocking additional memory
Using a function for initialization will also enable you to generate a map in an initializer, but avoids nasty side-effects:
Map<String, String> myMap = createMap();
private static Map<String, String> createMap() {
Map<String,String> myMap = new HashMap<String,String>();
myMap.put("a", "b");
myMap.put("c", "d");
return myMap;
}
Can I declare and initialize a map in java with a literal?
For Java 9 and beyond, you can make use of Map#of
, as well as Map#ofEntries
with Map#entry
:
Map<String, String> example = Map.ofEntries(
Map.entry("1", "one"),
Map.entry("2", "two"),
Map.entry("3", "three"),
//...
);
For shorter literals (10 or less entries), you can use Map#of
directly (albeit with a slightly confusing syntax of Key1, Value1, Key2, Value2, ...
):
Map<String, String> example = Map.of("1", "one", "2", "two");
Prior to Java 9, this would typically only be needed for initializing constant Map
objects, for which a static
initializer block is also useful:
private static final Map<String, String> MY_CONSTANT;
static {
Map<String, String> setup = new HashMap<>();
setup.put("1", "one");
setup.put("2", "two");
setup.put("3", "three");
MY_CONSTANT = Collections.unmodifiableMap(setup);
}
This will allow you to create a constant Map
while allowing you to modify the map before it is set.
As pointed out by @Pshemo, there are numerous reasons to avoid double-brace initialization, however the notable exception to the "rule" is typically in constants much like the above example (as numerous anonymous classes would not be made). However, it is still possible to work around the need for double-brace initialization even this case, so it is overall best to avoid if possible. The only case I can think of this not being possible is within the context of a constant within an enum
class, where the double-brace init may truly be the only true way to make this work.
Literal declaration of HashMap in Java
Though {{
(double brace) is an anti pattern, something like this you can write
HashMap<String, String> map = new HashMap<String, String>(){{
put("Key 1", "Value 1");
put("Key 2", "Value 2");
put("Key 3", "Value 3");
}};
Edit :
If you are looking for a better way to put elements, iterate over your json and put key values in a loop.
How can I initialise a static Map?
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:
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);
}
}
Java - instantiate a hashmap from literal value pairs
Since you are using Java 8 you can use streams and collectors to achieve this.
import java.util.AbstractMap.SimpleEntry;
import java.util.stream.Collectors;
import java.util.stream.Stream;
...
Map<String, String> map = Stream.of(
new SimpleEntry<>("key1", "value1"),
new SimpleEntry<>("key2", "value2"))
.collect(Collectors.toMap(SimpleEntry::getKey, SimpleEntry::getValue));
It is pretty verbose but has a substantial advantage over the static initialisation method - the class which instantiates the map this way is not referenced by it. In the case of static initialisation the anonymous class created with new HashMap<>(){...}
will hold a reference to the class that created it and the latter cannot be garbage collected until the map itself is.
HashMap initialization in java
Yes it is possible:
public static <K,V> Map<K,V> mapFromArrays(K[] keys,V[]values){
HashMap<K, V> result=new HashMap<K, V>();
for(int i=0;i<keys.length;i++){
result.put(keys[i], values[i]);
}
return result;
}
Assuming that keys and values have the same length.
You may also use this function in a static initializer like this:
private static Integer[] keys=new Integer[]{1,2,3};
private static String[] values=new String[]{"first","second","third"};
private static Map<Integer,String> myMap;
{
myMap=mapFromArrays(keys, values);
}
Correct way to initialize HashMap and can HashMap hold different value types?
It really depends on what kind of type safety you need. The non-generic way of doing it is best done as:
Map x = new HashMap();
Note that x
is typed as a Map
. this makes it much easier to change implementations (to a TreeMap
or a LinkedHashMap
) in the future.
You can use generics to ensure a certain level of type safety:
Map<String, Object> x = new HashMap<String, Object>();
In Java 7 and later you can do
Map<String, Object> x = new HashMap<>();
The above, while more verbose, avoids compiler warnings. In this case the content of the HashMap
can be any Object
, so that can be Integer
, int[]
, etc. which is what you are doing.
If you are still using Java 6, Guava Libraries (although it is easy enough to do yourself) has a method called newHashMap()
which avoids the need to duplicate the generic typing information when you do a new
. It infers the type from the variable declaration (this is a Java feature not available on constructors prior to Java 7).
By the way, when you add an int or other primitive, Java is autoboxing it. That means that the code is equivalent to:
x.put("one", Integer.valueOf(1));
You can certainly put a HashMap
as a value in another HashMap
, but I think there are issues if you do it recursively (that is put the HashMap
as a value in itself).
HashMap cant be initialized with loop? Initialize HashMap from textfile
As stated in the comments, you should be using a new instance of ArrayList
each time you determine the key has changed, otherwise you are simply re-using the same ArrayList
for EVERY key
The following example demonstrates a modified version of your code, so that when the code detects a new key, and the previous key is not blank, it will map the key
to the current instance of the ArrayList
.
It will then create a new instance of an ArrayList
and place all the preceeding values into it
File file = new File(System.getProperty("user.dir") + "/data.txt");
Map<String, List<String>> map = new HashMap<String, List<String>>();
try (Scanner scan = new Scanner(file);) {
String key = "";
List<String> value = new ArrayList<String>();
while (scan.hasNextLine()) {
String line = scan.nextLine();
if (line.contains("!")) {
if (!key.trim().isEmpty()) {
map.put(key, value);
System.out.println(key + " , " + value);
}
key = line;
key = key.replaceAll("!", "");
value = new ArrayList<String>();
} else {
value.add(line);
}
}
if (!key.trim().isEmpty() && !value.isEmpty()) {
map.put(key, value);
}
scan.close();
System.out.println(map.get("first")); //This prints the second category
System.out.println(map.get("second"));
} catch (Exception e) {
e.printStackTrace();
}
Related Topics
How to Gracefully Handle the Sigkill Signal in Java
Using Regular Expressions to Extract a Value in Java
Difference Between File.Separator and Slash in Paths
How to Find Files That Match a Wildcard String in Java
How to Set the Default Locale in the Jvm
Regex Doesn't Work in String.Matches()
Using Setdate in Preparedstatement
Generate/Get Xpath from Xml Node Java
Cut Out Image in Shape of Text
Can't Add Value to the Java Collection with Wildcard Generic Type
Why Does Writeobject Throw Java.Io.Notserializableexception and How to Fix It
Scale the Imageicon Automatically to Label Size
Centering a Jlabel on a JPAnel
What Is an Outofmemoryerror and How to Debug and Fix It