I am a Java beginner. Recently I try to study the Java code of my company system and I come up with a very confusing data structure. It is a static variable of HashMap, but the HashMap is type of it class...
This is the example.
public class CustomerList{
static ByteHashMap<CustomerList> Element1 = new HashMap<CustomerList>();
static ByteHashMap<CustomerList> Element2 = new HashMap<CustomerList>();
static ByteHashMap<List<CustomerList>> Element1 = new HashMap<List<CustomerList>>();
....
}
Can anyone explain to me the purpose of this kind of data structure? And in what perspective should I understand this data structure?
edit: The ByteHashMap is come from a open source library
I doubt what you published is valid code because Map or HashMap takes 2 parameter types i.e. Map<K, V>.
If you are actually asking about the practice to set a static structure of its own type on the class level, then yes its OK. It's a convenient way to keep a global collection of a certain class. One sample usage is when you want to ensure == equality when object equals and to return the unique instance.
In first example of HashMap, we will create and add object into our Map. Always use Generics, if you are not working in Java 1.4. Following code will create HashMap with keys of type String and values of type Integer with default size and load factor.
HashMap<String, Integer> cache = new HashMap<String, Integer>();
alternatively you can create HashMap from copying data from another Map or Hashtable as shown in below example:
Hashtable<Integer, String> source = new Hashtable<Integer,String>();
HashMap<Integer, String> map = new HashMap(source);
You can also supply load factor (percentage of size, which if fulled trigger resize of HashMap) and initialiCapacity while creating instance by using overloaded constructor provided in API. Adding elements, also called put operation, requires key and value object. Here is an example of adding key and value in Java HashMap:
map.put(21, "Twenty One");
map.put(21.0, "Twenty One"); //this will throw compiler error because 21.0 is not integer
for more details please refer
http://java67.blogspot.in/2013/02/10-examples-of-hashmap-in-java-programming-tutorial.html
Related
I'm having trouble trying to initiate an arraylist in which the first column I want to be a string, and the second column be a custom object.
For example column [0] be String, and column[1] be an Integer. Convention attempts of creating a multidimensional arraylist as in those used by int[][] or String[][] don't seem to work :( I would welcome any help. At this point I don't think it's something java allows. I can make it work for just one type of object but it's not what I want. Thanks!
Do you need an arraylist? You could create a Map<String, Object> or Map<String, Integer> or whatever you need..
Sure it does, but you weaken/eliminate type-checking:
Map myMap<String>, Integer> myData = new HashMap<String, Integer>();
Now your list of strings can be retrieved by myMap.keySet() and values can be retrieved by myMap.values(). Each of these return a Set, which you can easily convert to a List using the following code:
List<String> strings = new ArrayList<String>(myMap.keySet()); // get your strings
List<Integer> numbers = new ArrayList<Integer>(myMap.values(); // get your numbers
Good luck and if you should run into problems, do leave a comment.
Arrays are geared towards one specific type of thing - be they Object or String or int. Despite the fact that you're adding multiple dimensions to them, they still only hold one type of information.
What you would rather have is a mapping between two objects. This allows you to do the following:
Associate any key to a particular value
Eliminate duplicate key entries
Be much easier to access instead of array indexing
Here's an example. Say your custom object is a Cat, and you want to map the name of the owner to a particular Cat. You create a new instance of a Map.
Map<String, Cat> catOwners = new HashMap<>();
You can then put elements into it...
catOwners.put("Jamie", new Cat("Tycho"));
...and retrieve them with relative ease.
Cat currentCat = catOwners.get("Jamie"); // gets Jamie's cat
if you really want to, you can even iterate over them using the Map.Entry object provided with all Maps:
for(Map.Entry<String, Cat> element : catOwners.entrySet()) {
System.out.println(element.getKey()
+ " owns " + element.getValue().getName());
}
What you can do is use the generic Object type, and cast accordingly.
I use a TreeMap as a 'key' inside another TreeMap
ie
TreeMap<TreeMap<String, String>, Object>
In my code 'object' is a personal construct, but for this intance I have used a string.
I have created a pair of TreeMaps to test the TreeMap.CompareTo() and TreeMap.HashCode() methods. this starts with the following...
public class TreeMapTest
public void testTreeMap()
{
TreeMap<String, String> first = new TreeMap<String, String>();
TreeMap<String, String> second = new TreeMap<String, String>();
first.put("one", "une");
first.put("two", "deux");
first.put("three", "trois");
second.put("une", "one");
second.put("deux", "two");
second.put("trois", "three");
TreeMap<TreeMap<String, String>, String> english = new TreeMap<TreeMap<String, String>, String>();
TreeMap<TreeMap<String, String>, String> french = new TreeMap<TreeMap<String, String>, String>();
english.put(first, "english");
french.put(second, "french");
From here I now call the the english item to see if it contains the key
if (english.containsKey(second))
{
System.out.println("english contains the key");
//throws error of ClassCastException: Java.util.TreeMap cannot be cast to
//Java.Lang.Comparable, reading the docs suggests this is the feature if the key is
//not of a supported type.
//this error does not occur if I use a HashMap structure for all maps, why is
//this key type supported for one map structure but not another?
}
However I should note that both HashMap and TreeMap point to the same HashCode() method in the AbstractMap parent.
My first thought was to convert my TreeMap to a HashMap, but this seemed a bit soppy! So I decided to apply the hashCode() method to the 2 treemap objects.
int hc1 = first.hashCode();
int hc2 = second.hashCode();
if(hc1 == hc2)
{
systom.out.printline("values are equal " + hc1 + " " + hc2);
}
prints the following
values are equal 3877431 & 3877431
For me the hashcode should be different as the key values are different, I can't find details on the implementation difference of the hashCode() method between HashMap and TreeMap.
Please not the following.
changing the Keys only to HashMap doesn't stop the ClassCastException error. Changing all the maps to a HashMap does. so there is something with the containsKey() method in TreeMap that isn't working properly, or I have missunderstood - can anyone explain what?
The section where I get the hashCode of the first and second map objects always produces the same output (no matter if I use a Hash or Tree map here) However the if(english.ContainsKey(second)) doesn't print any message when HashMaps are used, so there is obviously something in the HashMap implementation that is different for the compareTo() method.
My principle questions are.
Where can I find details of the types of keys for use in TreeMap objects (to prevent future 'ClassCastException' errors).
If I can't use a certain type of object as a key, why am I allowed to insert it as a key into the TreeMap in the first place? (surely if I can insert it I should be able to check if the key exists?)
Can anyone suggest another construct that has ordered inster / retrieval to replace my TreeMap key objects?
Or have I potentially found strange behaviour. From my understanding I should be able to do a drop in replacement of TreeMap for HashMap, or have I stumbled upon a fringe scenario?
Thanks in advance for your comments.
David.
ps. the problem isn't a problem in my code as I use a personal utility to create a hash that becomes dependent on the Key and Value pairs (ie I calculate key hash values differently to value hash values... sorry that if is a confusing sentence!) I assume that the hashCode method just sums all the values together without considering if a item is a key or a value.
pps. I'm not sure if this is a good question or not, any pointers on how to improve it?
Edit.
from the responses people seem to think I'm doing some sort of fancy language dictionary stuff, not a surprise from my example, so sorry for that. I used this as an example as it came easily to my brain, was quick to write and demonstrated my question.
The real problem is as follows.
I'm accessing a legacy DB structure, and it doesn't talk nicely to anything (result sets aren't forward and reverse readable etc). So I grab the data and create objects from them.
The smallest object represents a single row in a table (this is the object that in the above example I have used a string value 'english' or 'french' for.
I have a collection of these rowObjects, each row has an obvious key (this is the TreeMap that points to the related rowObject).
i don't know if that makes things any clearer!
Edit 2.
I feel I need to elaborate a little further as to my choice of originaly using
hashMap<HashMap<String,string>, dataObject>
for my data structure, then converting to TreeMap to gain an ordered view.
In edit 1 I said that the legacy DB doesn't play nicely (this is an issue with the JDBC.ODBC I suspect, and I'm not about to acquire a JDBC to communicate with the DB). The truth is I apply some modifications to the data as as I create my java 'dataObject'. This means that although the DB may spit out the results in ascending or descending order, I have no way of knowing what order they are inserted into my dataObject. Using a likedHashMap seems like a nice solution (see duffymo's suggestion) but I later need to extract the data in an ordered fashion, not just consecutively (LinkedHashMap only preserves insertion order), and I'm not inclined to mess around with ordering everything and making copies when I need to insert a new item in between 2 others, TreMap would do this for me... but if I create a specific object for the key it will simply contain a TreeMap as a member, and obviously I will then need to supply a compareTo and hashCode method. So why not just extent TreeMap (allthough Duffymo has a point about throwing that solution out)!
This is not a good idea. Map keys must be immutable to work properly, and yours are not.
What are you really trying to do? When I see people doing things like this with data structures, it makes me think that they really need an object but have forgotten that Java's an object-oriented language.
Looks like you want a crude dictionary to translate between languages. I'd create a LanguageLookup class that embedded those Maps and provide some methods to make it easier for users to interact with it. Better abstraction and encapsulation, more information hiding. Those should be your design objectives. Think about how to add other languages besides English and French so you can use it in other contexts.
public class LanguageLookup {
private Map<String, String> dictionary;
public LanguageLookup(Map<String, String> words) {
this.dictionary = ((words == null) ? new HashMap<String, String>() : new HashMap<String, String>(words));
}
public String lookup(String from) {
return this.dictionary.get(from);
}
public boolean hasWord(String word) {
return this.dictionary.containsKey(word);
}
}
In your case, it looks like you want to translate an English word to French and then see if the French dictionary contains that word:
Map<String, String> englishToFrenchWords = new HashMap<String, String>();
englishToFrenchWords.put("one", "une");
Map<String, String> frenchToEnglishWords = new HashMap<String, String>();
frenchToEnglishWords.put("une", "one");
LanguageLookup englishToFrench = new LanguageLookup(englishToFrenchWords);
LanguageLookup frenchToEnglish = new LanguageLookup(frenchToEnglishWords);
String french = englishToFrench.lookup("one");
boolean hasUne = frenchToEnglish.hasWord(french);
Your TreeMap is not Comparable so you can't add it to a SortedMap and its not immutable so you can't add it to a HashMap. What you could use an IdentityMap but suspect an EnumMap is a better choice.
enum Language { ENGLISH, FRENCH }
Map<Language, Map<Language, Map<String, String>>> dictionaries =
new EnumMap<>(Language.class);
Map<Language, Map<String, String>> fromEnglishMap = new EnumMap<>(Language.class);
dictionaries.put(Language.ENGLISH, fromEnglishMap);
fromEnglishMap.put(Language.FRENCH, first);
Map<Language, Map<String, String>> fromFrenchMap = new EnumMap<>(Language.class);
dictionaries.put(Language.FRENCH, fromFrenchMap);
fromEnglishMap.put(Language.ENGLISH, second);
Map<String, String> fromEnglishToFrench= dictionaries.get(Language.ENGLISH)
.get(Language.FRENCH);
To the problem why Hashmap works and Treemap does not:
A Treemap is a "sorted map", meaning that the entries are sorted according to the key. This means that the key must be comparable, by implementing the Comparable interface. Maps usually do NOT implement this, and I would highly suggest you do not create a custom type to add this feature. As duffymo mentions, using maps as keys is a BAD idea.
i want to create an LinkedList of couple that the key is a String and the value is an integer ?
LinkedList doesn't have a key. It's a list of elements, not a key/value mapping.
If you want a LinkedList where each element is a pair of Integer/String values, you'll need to pick one of:
Create a generic Pair class
(Ab)use an existing generic class (e.g. Map.Entry)
Create a custom class for your specific scenario
I would suggest the last option as the most sensible one - you'll be able to give it appropriate semantics and names according to the real meaning of the string and the integer. Heck, you'll also be able to avoid boxing the integer, as you can have:
public class WhateverYouCallIt {
private final int firstValue;
private final String secondValue;
// Constructor, properties
}
You can only use Object in a LinkedList., this means you cant use Java Primitives.
However, what you seem to need is a Map structure.
I recommend using java.util.HashMap, it allows you to create a Key, Value pairs.
Example:
HashMap<String,Integer> a = new HashMap<String,Integer>();
a.put("one",1);
a.put("two",2);
System.out.println(a.get("one"));
//prints 1
System.out.println(a.get("two"));
//prints 2
EDIT:
As per your comment, i see you required order, use the following example then:
LinkedHashMap<String, Integer> b = new LinkedHashMap<String,Integer>();
b.put("one",1);
b.put("two",2);
b.put("a",3);
for (String key:b.keySet())
{
System.out.println(b.get(key)); // print 1 then 2 finally 3
}
Hope this is what you were asking (if so, modify your question).
One error is you need Integer instead of int, but as others have pointed out LinkedList doesn't take Key/Value pairs.
I'd imagine a HashMap is what your after. As other have stated, you cannot use a primitive type such as "int" in a library storage class like LinkedList, or ArrayList, you must instead use an object such as "Integer".
HashMap hash = new HashMap();
Read this for more information: http://docs.oracle.com/javase/1.4.2/docs/api/java/util/HashMap.html
I have a need to store a list of dynamically created objects in a way where they can all be retrieved and their methods called on demand.
As far as I can see for the list and creation, a HashMap fits my needs but i'm a bit puzzled on recalling the objects and calling their methods using the HashMap.
Just as a reference, let me give you a little code:
Here is the HashMap:
Map<String, Object> unitMap = new HashMap<String, Object>();
// here is how I put an object in the Map notice i'm passing coordinates to the constructor:
unitMap.put("1", new Worker(240, 240));
unitMap.put("2", new Worker(240, 240));
Now I need to create a method that retrieves every object in the hashmap and call a method from each object. is this possible or can the created objects only be referenced directly. If so, is there another way to call a method of all existing instances of a class dynamically (in other words, on user input)?
Sure. You can do this:
for (Object thing : unitMap.values()) {
// use "thing" here
}
If you need the keys too, you can either get just the keys:
for (String key : unitMap.keySet()) {
// use "key" here
}
or both the keys and values together:
for (Map.Entry<String, Object> entry : unitMap.entrySet()) {
// use "entry.getKey()" and "entry.getValue()"
}
In all the above cases, each entry in the map is traversed one by one. So at the end of the loop, you'll have processed all the entries in the map.
If all of the values in the Map are Worker objects, you should declare your map to be of type Map<String, Worker>. This way, when you pull a value out of the map, it will be typed as a Worker. This way you can call any method declared on Worker as opposed to having to check the type at runtime using instanceof.
If the map holds different values, and you need to keep the value type as Object, it may be advantageous to use an interface to define the method that you want to call for each different object type.
If you do not know what method you want to run on the values until runtime, and the map can hold different values, you will just have to do what you are currently doing, and use Map<String, Object>.
Finally, to get the values of the map, you do just as Chris Jester-Young mentioned before me. The biggest advantage, as I said previously, is that your objects will be typed, and you will have no need for casting/instanceof checking.
I use this to put all values from hashMap on a List, hope it helps.
private List<String> getValuesFromHashMap(HashMap<String, String> hashMap) {
List<String> values = new ArrayList<String>();
for (String item : hashMap.values()) {
values.add(item);
}
return values;
}
I have a HashMap having key as my own object and key as ArrayList of String. Is there a way to get the key object from the map which is equal to another object without iterating the map. Please note that my object has implemented equals & hashcode. And it only uses 2 attribute of the class to compare. The another object which I am trying to find in the keys of the map has those 2 attribute equal but the other attributes may be different in the key of the map.
//The actual map
private HashMap<FileDetail, ArrayList<String>> map = new HashMap<FileDetail, ArrayList<String>>();
//object to search in above map without iteration.
FileDetail file = some object;
I want to get the reference of the "file" object in the keys of the map.
No you can't do that. HashMap are supposed to work the other way : you have the key, you're looking for the object.
If you have an object and you want to find the key, there's probably something wrong in your logic and your looking in a wrong direction to solve your problem.
If you don't want to iterate over the keySet, then you can use Guava's BiMap. A biMap has an inverse view which is another bimap containing reversed keys and values. This is how you would use it:
BiMap<FileDetail, ArrayList<String>> biMap = HashBiMap.create();
//object to search in above map without iteration.
FileDetail file = some object;
FileDetail key = biMap.inverse().get(biMap.get(file));
If you really need to do this without iteration over the keySet (e.g. because the map is very large), I suggest storing both the key and the list as values in the map. Either create some specific class encapsulating both, or use a simple pair class. The map would look like:
Map<FileDetail, Pair<FileDetail, List<String>>>
If you can't change the type of the map, you can use a second Map<FileDetail, FileDetail> where key and value are always the same objects.
This question is five years old, but I had the same question just today, and found this page. I thought I'd share the solution I decided upon using, which is not described in any of the existing answers and avoids iterating over all the keys in the map. (Please be gentle; this is my first posting on SO. It's tough finding questions I can answer that don't already have answers. Moreover, every question I've had to date has already been asked on SO. I've been using SO for years, with no ability to comment or vote on answers.)
As has been stated already, maps are designed so that when you have a key, you look up a value. That being the case, the answer is to use the key also as the value, so that when you perform a lookup using an arbitrary key, which equals your original key but is not necessarily == to it, you get back the original key. The issue then, is how to get what you originally intended to be the value.
My solution depends on having control of the class used for the key, and control of the map, with the ability to redefine them, which appears to be the case for the OP. In the OP's example, this would be control of the FileDetail class and of the private map variable. Assuming such control, the FileDetail class would be modified to contain a member variable of type ArrayList<String>, which for my sample code below I'll call list, with associated setter and getter methods. For the private map variable, it would be defined thusly:
private HashMap<FileDetail, FileDetail> map = new HashMap<>();
Now, when you want to put a new ArrayList<String> object in the map, assigned to a specific FileDetail key, you assign the ArrayList<String> object to the FileDetail's ArrayList<String> member variable instead, and then place the FileDetail object in the map.
public void putInMap(FileDetail fd, ArrayList<String> al) {
// Ignoring null conditions for simplicity...
fd.setList(al);
map.put(fd, fd);
}
Later, when you get some arbitrary FileDetail object (one that equals the key but isn't necessarily == to it), and you want the associated key, it's a matter of doing a normal lookup:
FileDetail otherFd = getArbitraryFileDetail();
FileDetail originalKeyFd = map.get(otherFd);
And to get the associated ArrayList<String> after having performed the above:
ArrayList<String> al = originalKeyFd.getList();
Certainly this all hinges on the implementations of the equals and hashCode methods of the FileDetail class, but the OP already had those methods defined as desired.
Hope this helps anyone who, like me, comes to this page with a similar situation.
You are likely looking for a Bidirectional Map, Apache Commons Collections includes this as part of the library (im sure there are other imeplementations as well.) A bidirectional map, just as the name implies, is a map but written so as to make looking up by key or by value efficient.
In Java, HashMap associates a key with a value, not the other way around.
You can retrieve a Set of all of the keys using HashMap.keySet(), or alternatively iterate over all of the entries using HashMap.entrySet():
for (Entry <FileDetail, ArrayList<String>> entry : map.entrySet()) {
FileDetail key = entry.getKey();
if (shouldProcess(key)) {
ArrayList<String> list = entry.getValue();
processList(list);
}
}
We get the key object from Hashmap without iterating the keyset of HashMap by converting keyset to ArrayList. This is a simple example:
//Creating hashmap
HashMap<String, String> map = new HashMap<String, String>();
//Adding elements into the map
map.put("1", "Amit");
map.put("2", "Ananth");
map.put("3", "Sunil");
//Get the list from keyset
ArrayList myKeyList = new ArrayList(map.keySet());
//object to search in above map without iteration.
String myobj = "3";
System.out.println(myKeyList.get(myKeyList.indexOf(myobj)));