Reputation: 2519
I am trying to compile the following code:
private String dataToString(){
Map data = (HashMap<MyClass.Key, String>) getData();
String toString = "";
for( MyClass.Key key: data.keySet() ){
toString += key.toString() + ": " + data.get( key );
return toString;
}
I get an error in the for line that says:
incompatible types found : java.lang.Object required: MyClass.Key
The getData()
method returns an Object
(but in this case the Object
returned has the HashMap
structure). MyClass.Key
is an enum that I have created for the purposes of my application (in another class file - MyClass
).
When I created a foreach loop with the same structure in MyClass.java
, I did not encounter this problem.
What am I doing wrong?
Upvotes: 37
Views: 101112
Reputation: 32901
Motlin's answer is correct.
I have two notes...
Don't use toString += ...
, but use StringBuilder
instead and append data to it.
Cast which Martin suggested will give you unchecked warning, which you won't be able to get rid of, because it is really unsafe.
Another way, without warning (and with StringBuilder):
private String dataToString(){
Map<?, ?> data = (Map<?, ?>) getData();
StringBuilder toString = new StringBuilder();
for (Object key: data.keySet()) {
toString.append(key.toString());
toString.append(": ");
toString.append(data.get(key));
}
return toString.toString();
}
This works, because toString method which you call on key
is defined in Object class, so you don't need casting at all.
Using entrySet
is even better way, as it doesn't need to do another look-up in map.
Upvotes: 3
Reputation: 2876
I found this simple example at java forum. Its syntax is very similar to the List's foreach, which was what I was looking for.
import java.util.Map.Entry;
HashMap nameAndAges = new HashMap<String, Integer>();
for (Entry<String, Integer> entry : nameAndAges.entrySet()) {
System.out.println("Name : " + entry.getKey() + " age " + entry.getValue());
}
[EDIT:] I tested it and it works perfectly.
Upvotes: 5
Reputation: 182802
A slightly more efficient way to do this:
Map<MyClass.Key, String> data = (HashMap<MyClass.Key, String>) getData();
StringBuffer sb = new StringBuffer();
for (Map.Entry<MyClass.Key,String> entry : data.entrySet()) {
sb.append(entry.getKey());
sb.append(": ");
sb.append(entry.getValue());
}
return sb.toString();
If at all possible, define "getData" so you don't need the cast.
Upvotes: 43
Reputation: 26738
Change:
Map data = (HashMap<MyClass.Key, String>) getData();
to
Map<MyClass.Key, String> data = (HashMap<MyClass.Key, String>) getData();
The problem is that data.keySet()
returns a Collection<Object>
if data is just a Map
. Once you make it generic, keySet()
will return a Collection<MyClass.Key>
. Even better... iterate over the entrySet()
, which will be a Collection<MyClass.Key, String>
. It avoids the extra hash lookups.
Upvotes: 38
Reputation: 3621
You could grab the entrySet instead, to avoid needing the key class:
private String dataToString(){
Map data = (HashMap<MyClass.Key, String>) getData();
String toString = "";
for( Map.Entry entry: data.entrySet() ) {
toString += entry.getKey() + ": " + entry.getValue();
}
return toString;
}
Upvotes: 5