If I want to create a new Multimap with simple defaults, I curently need to do something like:
private final Multimap<Key, Value> providersToClasses = Multimaps
.newListMultimap(
new HashMap<Key, Collection<Value>>(),
new Supplier<List<Value>>() {
#Override
public List<Value> get() {
return Lists.newArrayList();
}
});
...because Java can't infer the correct types if Maps.newHashMap is used for the backing map. Of course, this can be refactored into a separate method, but is there already a way to write it more concisely?
Why aren't you using ArrayListMultimap.create() for such a simple case? It's the default way to create the simple HashMap/ArrayList that is probably the most common used multimap.
I run into this problem when writing clients and building up maps of query params. A nice succinct pattern I like for constructing multi-maps is to use ImmutableMultiMap#builder
Multimap<String, String> queryParams =
ImmutableMultimap.<String, String>builder()
.put("key-1", "value-1")
.put("key-1", "value-2")
.build();
The Guava documentation states that the create method advocated by some other answers "will soon be deprecated" in favour of the different forms presented below, and should therefore be avoided.
From Guava 21.0 onwards, the recommended way of creating a Multimap object where values are stored in ArrayList collections is the following:
MultimapBuilder.hashKeys().arrayListValues().build();
You can also use parameters if you want to specify the expected number of keys in your map and the expected number of values per key:
MultimapBuilder.hashKeys(expectedKeys).arrayListValues(expectedValuesPerKey).build();
Finally, you can create a new Multimap from an existing one using this construct:
MultimapBuilder.hashKeys().arrayListValues().build(multimap);
If you want to use data structures other than ArrayLists in your Multimap, you can replace the call to arrayListValues() by a number of other ones, listed here.
Here is compact solution:
Multimap<Integer, String> multi = HashMultimap.create();
In Java 8 this is much nicer, for all kinds of multimaps. This is for two reasons:
Because the compiler uses target types for type inference, you don't have to provide explicit type arguments for the HashMap contructor.
Constructor method references can be used to create the ArrayList factory.
It looks like this:
Multimap<Key, Value> providersToClasses =
Multimaps.newListMultimap(new HashMap<>(), ArrayList::new);
To answer the original type inference problem, though, you can also specify the generic types on a static method using Maps.<Key, Collection<Value>>newHashMap(), but it's certainly not more concise than new HashMap<Key, Collection<Value>>() (it may be more consistent).
Related
Is there a data structure in Java which can hold more than 4 values?
So something along the lines of
Map<String, String, String, String>;
This is needed to be able to reduce the number of if else statements I have. I would like to be able to do the following.
check if the data structure contains an element which matches a certain value, if it does then it assigns a link(which is string) to a variable and then adds a code and message to another variable which is related to that link.
if not is there a good workout around to achieve this?
Is there a data structure in Java which can hold more than 4 values?
There are lots of them.
The simplest is probably String[] which can hold 4 strings if you instantiate it like this:
new String[4]
And other Answers give other data structures that might meet your actual (i.e. unstated) requirements.
However, it is probably possible ... let alone sensible ... for us to enumerate all of the possible data structures that can meet your stated requirement.
Hint: you should try to explain how this data structure needs to work.
Hint 2: "the lines of Map<String, String, String, String>" does not help us understand your real requirement because we don't know what you mean by that.
UPDATE - Your explanation is still extremely vague, but I think you need something like this:
Map<String, MyRecord>;
public class MyRecord {
private String link;
private String code;
private String message;
// add constructor, getters, setters as required
}
There is nothing in the standard libraries, but Guava has a nice implementation; called
Multimap
If Guava is not an option in your environment, you will have to re-invent the wheel though.
Use can use MultiMap on Apache,
A MultiMap is a Map with slightly different semantics. Putting a value into the map will add the value to a Collection at that key. Getting a value will return a Collection, holding all the values put to that key
MultiMap mhm = new MultiValueMap();
mhm.put(key, "A");
mhm.put(key, "B");
mhm.put(key, "C");
Collection coll = (Collection) mhm.get(key);
Use Map of map:
Map<String, Map<String, Map<String, String>>>
Reading your question, It seams like you simply need a 'key-value' pair. Key being a 'String', which you have referred as 'a certain value' in your question. Value is a kind of wrapper object wrapping three Strings which you have referred as 'link, code and message'.
I suggest you can simply use
HashMap < String, Wrapper > map;
You can create a class ' Wrapper.java' which can contain three Strings, as instance fields
String link,code,message;
You can instantiate these fields in constructor and later can retrieve them using getter methods or also can have setters to set the values you need. You can provide a better contextual name to the class 'Wrapper.java'.
I need a double table from which I get two values from a key or index. I have seen this question already and I want to know what would be a better approach considering also performance.
1) Create a HashMap on this way:
HashMap<Integer, HashMap<String, String>> = ...;
I don't know how to put values inside this the put method, I have this and Eclipse gives me an error prueba.put(0, new Hashtable<"Hi", "Bye">); As you can see I have never used something like this before I am sure is a simple question.
2) Create a HashMap on this way:
HashMap<Integer, YourFancyDatatype>
So I create a class which pack the two or more values I want to have in one Object inside a single key or index.
Which would perform better ? Also if you can help me about how to use number 1) approach. The HashMap will have about 20000 entries.
Thank you very much for your time and help :)
You would want something with a single key and a collection of values. I would suggest using Apache's MultiMap, as they already implement this functionality for you.
Your first approach uses the same datastructure as provided by the Guava's HashBasedTable so you can use it instead.
But if you want the best performance you could try to use something based on arrays (e.g. Guava's ArrayTable)
Anyway I suggest to make some simple performance tests to check which solution performs better.
It you want to do an "in-line" put, you can do this:
prueba.put(0, new HashMap<String, String>() {{put("Hi", "Bye");}});
This employs an anonymous subclass of HashMap that has an instance block that loads the values.
Note that this will create one extra class for the JVM (called MyClass$1 or similar).
I don't know how to put values inside this the put method, I have this
and Eclipse gives me an error prueba.put(0, new Hashtable<"Hi",
"Bye">); As you can see I have never used something like this before I
am sure is a simple question.
Firstly, Hashtable<String, String> is not a subtype of HashMap<String,String>. your HashMap expects a HashMap<String, String> as a value. either insert a hashmap into values or change your hashmap declaration to :
HashMap<Integer, ? extends Map<String, String>> = ...;
however your 2nd approach is more object oriented. so i'd recommend using 2nd approach
The second one would probably be easier in your case in this way
HashMap<Integer, HashMap<String, FancyDataType>> h= ...;
this is how you'll have to insert the data
h=HashMap<Integer, FancyDataType> new Hashtable<Integer,FancyDataType>();
numbers.put(0, new FancyDataType("o","x"));
numbers.put(1, new FancyDataType("t","y"));
numbers.put(1, new FancyDataType("q","z"));
/// ...so one for all 20000
Assuming FancyDataType is something like
class FancyDataType{
String k,v;
FancyDataType(String k,String v){
this.k=k;this.v=v;
}
}
There are utility methods to create ImmutableMap like Immutable.of(Key, value) and its overload.
But such methods don't exist for HashMap or LinkedHashMap in Maps class.
Is there any better way to do this or Guava assumes such a map is always a constant map and ImmutableMap is best option to go with and don't need to provide a utility for HashMap.
Why would you want those for a regular HashMap or LinkedHashMap? You can just do this:
Map<String, Object> map = Maps.newHashMap();
map.put(key, value);
The thing with ImmutableMap is that it is a little bit more cumbersome to create; you first need to make a Builder, then put the key-value pairs in the builder and then call build() on it to create your ImmutableMap. The ImmutableMap.of() method makes it shorter to write if you want to create an ImmutableMap with a single key-value pair.
Consider what you'd have to write if you wouldn't use the ImmutableMap.of() method:
ImmutableMap<String, Object> map = ImmutableMap.builder()
.put(key, value);
.build();
Try Maps.newHashMap(ImmutableMap.of(...))
Maps.newHashMap(Map map)
The difference is that for an immutable map, you have to provide everything up-front, because you can't change it after construction. For mutable maps, you can just create the map and then add the entries. Admittedly this makes it slightly harder to create a map in a single expression, but that doesn't tend to be a problem where you'd want a mutable map anyway, in my experience.
cannot you use the copyOf method of ImmutableMap described here?
it should be something like
Map newImmutableMap = ImmutableMap.copyOf(yourMap);
ImmutableMap.of() returns a hash based immutable map without order.
If you need ordered immutable map, ImmutableSortedMap.of() is a choice.
ImmutableSortedMap provides methods such as firstKey(), lastKey(), headMap(K) and tailMap(K);
Both classes provide copyOf(Map) method.
So I have two questions about HashMaps in Java:
What is the correct way to initialize a HashMap? I think it might be best in my situation to use:
HashMap x = new HashMap();
But Eclipse keeps suggesting that I use:
HashMap<something, something> map = new HashMap();
Which is better?
Can a HashMap hold different types of objects/data types as values? For example, would this work and be OK:
map.put("one", 1);
map.put("two", {1, 2});
map.put("three", "hello");
In the first put(), I want an int as a value, in the second an int[], and third a string. Is this okay to do in Java with HashMaps? Also, is it okay to store a HashMap as a value within a HashMap?
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).
This is a change made with Java 1.5. What you list first is the old way, the second is the new way.
By using HashMap you can do things like:
HashMap<String, Doohickey> ourMap = new HashMap<String, Doohickey>();
....
Doohickey result = ourMap.get("bob");
If you didn't have the types on the map, you'd have to do this:
Doohickey result = (Doohickey) ourMap.get("bob");
It's really very useful. It helps you catch bugs and avoid writing all sorts of extra casts. It was one of my favorite features of 1.5 (and newer).
You can still put multiple things in the map, just specify it as Map, then you can put any object in (a String, another Map, and Integer, and three MyObjects if you are so inclined).
Eclipse is recommending that you declare the type of the HashMap because that enforces some type safety. Of course, it sounds like you're trying to avoid type safety from your second part.
If you want to do the latter, try declaring map as HashMap<String,Object>.
The way you're writing it is equivalent to
HashMap<Object, Object> map = new HashMap<Object, Object>();
What goes inside the brackets is you communicating to the compiler what you're going to put in the HashMap so that it can do error checking for you. If Object, Object is what you actually want (probably not) you should explicitly declare it. In general you should be as explicit as you can with the declaration to facilitate error checking by the compiler. What you've described should probably be declared like this:
HashMap<String, Object> map = new HashMap<String, Object>();
That way you at least declare that your keys are going to be strings, but your values can be anything. Just remember to use a cast when you get a value back out.
The 2nd one is using generics which came in with Java 1.5. It will reduce the number of casts in your code & can help you catch errors at compiletime instead of runtime. That said, it depends on what you are coding. A quick & dirty map to hold a few objects of various types doesn't need generics. But if the map is holding objects all descending from a type other than Object, it can be worth it.
The prior poster is incorrect about the array in a map. An array is actually an object, so it is a valid value.
Map<String,Object> map = new HashMap<String,Object>();
map.put("one",1); // autoboxed to an object
map.put("two", new int[]{1,2} ); // array of ints is an object
map.put("three","hello"); // string is an object
Also, since HashMap is an object, it can also be a value in a HashMap.
A HashMap can hold any object as a value, even if it is another HashMap. Eclipse is suggesting that you declare the types because that is the recommended practice for Collections. under Java 5. You are free to ignore Eclipse's suggestions.
Under Java 5, an int (or any primitive type) will be autoboxed into an Integer (or other corresponding type) when you add it to a collection. Be careful with this though, as there are some catches to using autoboxing.
Eclipse is suggesting you to define generic type so that you can have type safety. You can write
Map m = new HashMap();
which does not ensure type safety but following will ensure type safety
Map<Object,Object> = new HashMap<Object,Object>();
The Object can be any type such as String, Integer etc.
Map.of literals
As of Java 9, there is yet another way to instantiate a Map. You can create an unmodifiable map from zero, one, or several pairs of objects in a single-line of code. This is quite convenient in many situations.
For an empty Map that cannot be modified, call Map.of(). Why would you want an empty set that cannot be changed? One common case is to avoid returning a NULL where you have no valid content.
For a single key-value pair, call Map.of( myKey , myValue ). For example, Map.of( "favorite_color" , "purple" ).
For multiple key-value pairs, use a series of key-value pairs. ``Map.of( "favorite_foreground_color" , "purple" , "favorite_background_color" , "cream" )`.
If those pairs are difficult to read, you may want to use Map.of and pass Map.Entry objects.
Note that we get back an object of the Map interface. We do not know the underlying concrete class used to make our object. Indeed, the Java team is free to used different concrete classes for different data, or to vary the class in future releases of Java.
The rules discussed in other Answers still apply here, with regard to type-safety. You declare your intended types, and your passed objects must comply. If you want values of various types, use Object.
Map< String , Color > preferences = Map.of( "favorite_color" , Color.BLUE ) ;
In answer to your second question: Yes a HashMap can hold different types of objects. Whether that's a good idea or not depends on the problem you're trying to solve.
That said, your example won't work. The int value is not an Object. You have to use the Integer wrapper class to store an int value in a HashMap
Is it possible to have multiple values for the same key in a hash table? If not, can you suggest any such class or interface which could be used?
No. That's kind of the idea of hash tables.
However, you could either roll your own with a Map<YourKeyObject, List<YourValueObject>> and some utility methods for creating the list if it's not present, or use something like the Multimap from Google Collections.
Example:
String key = "hello";
Multimap<String, Integer> myMap = HashMultimap.create();
myMap.put(key, 1);
myMap.put(key, 5000);
System.out.println(myMap.get(key)); // prints either "[1, 5000]" or "[5000, 1]"
myMap = ArrayListMultimap.create();
myMap.put(key, 1);
myMap.put(key, 5000);
System.out.println(myMap.get(key)); // always prints "[1, 5000]"
Note that Multimap is not an exact equivalent of the home-baked solution; Hashtable synchronizes all its methods, while Multimap makes no such guarantee. This means that using a Multimap may cause you problems if you are using it on multiple threads. If your map is used only on one thread, it will make no difference (and you should have been using HashMap instead of Hashtable anyway).
Values of a hash table is Object so you can store a List
In a hashtable, one would use a key/value pair to store information.
In Java, the Hashtable class accepts a single value for a single key. The following is an example of an attempt to associate multiple values to a single key:
Hashtable<String, String> ht = new Hashtable<String, String>();
ht.put("Answer", "42");
ht.put("Hello", "World"); // First value association for "Hello" key.
ht.put("Hello", "Mom"); // Second value association for "Hello" key.
for (Map.Entry<String, String> e : ht.entrySet()) {
System.out.println(e);
}
In an attempt to include multiple values ("World", "Mom") to a single key ("Hello"), we end up with the following result for printing the entries in the Hashtable:
Answer=42
Hello=Mom
The key/value pair of "Hello" and "World" is not in the Hashtable -- only the second "Hello" and "Mom" entry is in the Hashtable. This shows that one cannot have multiple values associate with a single key in a Hashtable.
What is really needed here is a multimap, which allows an association of multiple values to a single key.
One implementation of the multimap is Multimap from Google Collections:
Multimap<String, String> mm = HashMultimap.create();
mm.put("Answer", "42");
mm.put("Hello", "World");
mm.put("Hello", "Mom");
for (Map.Entry<String, String> e : mm.entries()) {
System.out.println(e);
}
This is similar to the example above which used Hashtable, but the behavior is quite different -- a Multimap allows the association of multiple values to a single key. The result of executing the above code is as follows:
Answer=42
Hello=Mom
Hello=World
As can be seen, for the "Hello" key, the values of "Mom" and "World" associated with it. Unlike Hashtable, it does not discard one of the values and replace it with another. The Multimap is able to hold on to multiple values for each key.
Rather than give yet another multipmap answer, I'll ask why you want to do this?
Are the multiple values related? If yes, then it's probably better that you create a data structure to hold them. If no, then perhaps it's more appropriate to use separate maps.
Are you keeping them together so that you can iterate them based on the key? You might want to look for an alternative indexing data structure, like a SkipList.
Just make your own:
Map<Object, List<Object>> multiMap = new HashMap<Object, List<Object>>();
To add:
public void add(String key, Object o) {
List<Object> list;
if (multiMap.containsKey(key)) {
list = multiMap.get(key);
list.add(o);
} else {
list = new ArrayList<Object>();
list.add(o);
multiMap.put(key, list);
}
}
As others pointed out, no. Instead, consider using a Multimap which can map many values for the same key.
The Google Collections (update: Guava) library contains one implementation, and is probably your best bet.
Edit: of course you can do as Eric suggests, and store a Collection as a value in your Hashtable (or Map, more generally), but that means writing unnecessary boilerplate code yourself. When using a library like Google Collections, it would take care of the low-level "plumbing" for you. Check out this nice example of how your code would be simplified by using Multimap instead of vanilla Java Collections classes.
None of the answers indicated what I would do first off.
The biggest jump I ever made in my OO abilities was when I decided to ALWAYS make another class when it seemed like it might be even slightly useful--and this is one of the things I've learned from following that pattern.
Nearly all the time, I find there is a relationship between the objects I'm trying to place into a hash table. More often than not, there is room for a class--even a method or two.
In fact, I often find that I don't even want a HashMap type structure--a simple HashSet does fine.
The item you are storing as the primary key can become the identity of a new object--so you might create equals and hash methods that reference only that one object (eclipse can make your equals and hash methods for you easily). that way the new object will save, sort & retrieve exactly as your original one did, then use properties to store the rest of the items.
Most of the time when I do that, I find there are a few methods that go there as well and before I know it I have a full-fledged object that should have been there all along but I never recognized, and a bunch of garbage factors out of my code.
In order to make it more of a "Baby step", I often create the new class contained in my original class--sometimes I even contain the class within a method if it makes sense to scope it that way--then I move it around as it becomes more clear that it should be a first-class class.
See the Google Collections Library for multimaps and similar such collections. The built-in collections don't have direct support for this.
What you're looking for is a Multimap. The google collections api provides a nice implementation of this and much else that's worth learning to use. Highly recommended!
Simple. Instead of
Hashtable<Key, Value>, use Hashtable<Key, Vector<Value>>.
You need to use something called a MultiMap. This is not strictly a Map however, it's a different API. It's roughly the same as a Map<K, List<V>>, but you wont have methods like entrySet() or values().
Apart from the Google Collections there is a apache Commons Collection object
for MultiMap
Following code without Google's Guava library. It is used for double value as key and sorted order
Map<Double,List<Object>> multiMap = new TreeMap<Double,List<Object>>();
for( int i= 0;i<15;i++)
{
List<Object> myClassList = multiMap.get((double)i);
if(myClassList == null)
{
myClassList = new ArrayList<Object>();
multiMap.put((double) i,myClassList);
}
myClassList.add("Value "+ i);
}
List<Object> myClassList = multiMap.get((double)0);
if(myClassList == null)
{
myClassList = new ArrayList<Object>();
multiMap.put( (double) 0,myClassList);
}
myClassList.add("Value Duplicate");
for (Map.Entry entry : multiMap.entrySet())
{
System.out.println("Key = " + entry.getKey() + ", Value = " +entry.getValue());
}