"my" code:
public void iterateHashmap2() {
HashMap hashmap = this.media;
Iterator it = hashmap.keySet().iterator();
while (it.hasNext())
{
Object key = it.next();
Object val = hashmap.get(key);
// doesn't work..
System.out.println(val.getAttribute);
}
}
So my question is, how do I get the attributes that the value contains. The value is a class I made myself, which contains 4 Strings and another class I made, as attributes.
(What I want to do is iterate through a hashmap and compare the String of an attribute that is stored in the value with input data.. so I need to be able to access the attributes in the values of the hashmap..hope that makes sense..)
You access values in a map by providing a key:
// create a map
Map<String, MyObject> map = new HashMap<String, MyObject>();
// store a value
map.put("key", someObject);
// retrieve a value
MyObject someObject2 = map.get("key");
You can also use
map.keySet() to retrieve all keys
map.values() to retrieve all values, without keys
map.entrySet() to retrieve all Mappings. Each Entry represents one key mapped to one value.
a) In my code I use Java Generics, because that has been the standard way to do it for at least 5 years now.
b) You should consider reading The Map Interface from the Java Tutorial.
a): If you are using JDK1.5 or higher, please use generic and enhanced loop. The code will much simpler and safer:
for(Map.Entry<Key, YourObj> entry: this.media.entrySet()){
System.out.println(entry.getValue().getAttribute());
}
b): If you have to use JDK1.4 or lower, you have to cast your object: ((YourObj)val).getAttribute();
Object val = hashmap.get(key);
// doesn't work..
System.out.println(val.getAttribute());
The problem here is that Java is statically typed, which means you would need to cast val in order to access non-Object methods. You need to cast val as the type actually in the hashmap, as you're not using generics.
MyClass val = (MyClass) hashmap.get(key);
Try changing this line:
Object val = hashmap.get(key);
to this line:
YourClass val = (YourClass) hashmap.get(key);
Since you are getting an Object type you cannot just call your class's method without first casting it correctly.
Btw you should seriously consider using Java Generics
You will need a cast to a your target object's type. Like:
YourObject val = (YourObject) hashmap.get(key);
But ...
Your Map should be generic like Map<KeyClass, ValueClass>
There is better way to iterate over a Map:
Example:
for (Map.Entry<KeyClass, ValueClass> entry : map.entrySet()) {
KeyClass key = entry.getKey();
ValueClass val = entry.getValue());
}
If your question is how to cast the value mapped to the key in the HashMap why not use generics to achieve that:
public void iterateHashmap2() {
HashMap<Object,YourClass> hashmap = this.media;
Iterator<YourClass> it = hashmap.keySet().iterator();
while (it.hasNext())
{
Object key = it.next();
YourClass val = hashmap.get(key);
// if YourClass has a getAttribute() method then this will work
System.out.println(val.getAttribute());
}
}
Also note that it's always good practice to work at interface level -- so this line:
HashMap<Object,YourClass> hashmap = this.media;
should be
Map<Object,YourClass> hashmap = this.media;
Related
I am trying to iterate through a hashmap which contains 8 entries. However one of these entries is a hashset 'balloon' with 2 objects within it. I want to add this to an array list so i can then iterate through it in a for loop/
First part of the code below works, I loop through the hashmap and look for the key I require which is 'balloon'. I need help to add the hashset to an array list.
I am getting a casting error when using Collectors.list and stream
//This is the hashmap I am looping through to find the balloon key
Map<String, Object> types = System.getPartyItems();
for (Map.Entry<String, Object> entry : types.entrySet()) {
if (StringUtils.contains(entry.getKey().toString(), "balloon")) {
//This is where I need to add the balloon hashset to a list to access the entries and values from within.
List<PartyItem> myPartyList = new ArrayList<>();
myPartyList.add (hash set of balloon objects)
Do i need to assign the hash set to a variable before i can set it to the list? Anything I've tried I am getting a casting error eg "class java.util.stream.ReferencePipeline$Head cannot be cast to class java.util.ArrayList"
Any help appreciated.
Thanks
Test if a value is a Set and if it is, add all items to your list.
if (StringUtils.contains(entry.getKey().toString(), "balloon")
&& entry.getValue() instanceof Set) {
myPartyList.addAll((Set)entry.getValue());
}
You can iterate like this:
for(String key: Map.keySet()){
if(StringUtils.contains(key, "balloon")){
Iterator<String> it = hashMap.get("balloon").iterator();
while(it.hasNext()){
// your code here
}
}
}
Instead of iterating through entry just iterate through keys and when you find the balloon get the hashset to iterate through it.
for(String key: types.keySet()){
if(StringUtils.contains(key, "balloon")){
for(Object object: types.get(key)){
//do what you need with object
}
}
}
After your edit it should be like this
for(String key: types.keySet()){
if(StringUtils.contains(key, "balloon")){
ArrayList<Set<PartyItem>> myList = new ArrayList();
myList.add(types.get(key));
}
}
Usually you structure your hashmap as <key, value> and you access your values via their corresponding keys. But they have to match exactly.
In your case your hashmap would look like this:
Map<String, Object> partyItems = myPartyList.getPartyItems();
// or maybe even
Map<String, PartyItem> partyItems = myPartyList.getPartyItems();
And getting the value is as easy as:
Object partyItem = partyItems.get("baloon");
If you are not sure if your paryItems contain a value for your key baloon you can check that first:
if (partyItems.contains("baloon")) {
Object partyItem = partyItems.get("baloon");
}
If you are looking for a part of the key matching baloon:
List<PartyItem> myFilteredPartyItems = partyItems.entrySet().stream()
.filter(e -> e.getKey().contains("baloon"))
.collect(Collectors.toList()))
This is called stream oriented programming (take a look at the Java Stream API), and if your run at least Java 8 you can use those.
And what it does, is turn the entries of the List to a stream, then remove everything which does not contain baloon in the key, and turn the resulting stream, which was not removed back to a list.
Here you also find a very informative tutorial on how to use streams in Java.
I was wondering how could i link my XSSFSheet by a string? I need a variable similar to Map, but it should return XSSFSheet, not object.
Something like this:
List<XSSFSheet, String> list = new ArrayList<XSSFSheet, String>
list.add(mySheet1, "ID154");
list.add(mySheet2, "ID4564");
list.get("ID4564"); //Gets mySheet1 by that ID
The easiest way to do so is a Map, but it would be a (very common) misuse of this datastructure. The correct way would be to create a simple dataholder class containing your two strings and have a List of objects of these datatypes.
On the other hand, reading your question again... a Map might not be so wrong at all in this case asy you have key-value-pairs.
So Map<String, XSSFSheet> map = new HashMap<>() should be what you're looking for.
No it is not. A list is an object for storing a collection of objects that are of the same type.to store key value pairs like what you want to do you'd need to use a HashMap object which is designed to store key, value pairs.
HashMaps come in the form HashMap<key, value> with key being the type for the key, and value being the type for the corresponding value.
Your code would then look like this:
HashMap<String, XSSFSheet> list = new HashMap<String, XSSFSheet>();
list.put("ID154", mySheet1);
list.put("ID4564", mySheet2);
list.get("ID4564"); //Gets mySheet1 by that ID
For more information read this page.
I don't think there is any structural overhead in using Map in your case.
Complexity of accessing an entry in a HashMap is O(m), where m is the number of elements in the longest linked list associated with an entry in a HashMap.
But if you are very much specific in not using Map, then you can make use of the KeyValue Tuple from the JavaTuples library.
A KeyValue is a Tuple from JavaTuples library that deals with only 2 elements – a key and a value.
Since this KeyValue is a generic class, it can hold any type of value in it.
Since KeyValue is a Tuple, hence it also has all the characterstics of JavaTuples:
They are Typesafe
They are Immutable
They are Iterable
They are Serializable
They are Comparable (implements Comparable)
They implement equals() and hashCode()
They also implement toString()
Class Declaration
public final class KeyValue<A, B> extends Tuple
implements IValueKey<A>, IValueValue<B>
Class hierarchy
Object ↳ org.javatuples.Tuple
↳ org.javatuples.KeyValue
So in your case you can use something like this.
Change according to your use case.
package com.test.UnitTests;
import java.util.*;
import org.javatuples.KeyValue;
class KeyValueTest {
public static void main(String[] args) {
KeyValue<Integer, String> kv1 = KeyValue.with(Integer.valueOf(1), "Maths");
KeyValue<Integer, String> kv2 = KeyValue.with(Integer.valueOf(2), "English");
List<KeyValue> testKVs = new ArrayList<KeyValue>();
testKVs.add(kv1);
testKVs.add(kv2);
//assuming that you want to fetch the value for key = 2
int key = 2;
String value = fetchValue(key,testKVs);
if(value!=null) {
System.out.println("Value for Key: "+key +" = "+value);
}else {
System.out.println("No Key-Value pair found with Key:"+key);
}
}
private static String fetchValue(int i, List<KeyValue> testKVs) {
for (KeyValue testKv : testKVs) {
if ((int) testKv.getKey() == i) {
return (String)testKv.getValue();
}
}
return null;
}
}
To learn about javatuples more, use this link:
https://www.geeksforgeeks.org/keyvalue-class-in-java-tuples/
You can download the jar at:
http://www.java2s.com/Code/Jar/j/Downloadjavatuples10jar.htm
I am trying to display the contents of the following HashMap :
HashMap<Character,Integer> hm = new HashMap<Character,Integer>();
I have used the following method to print out the contents :
Set hmset = hm.entrySet();
Iterator iterator = hmset.iterator();
while(iterator.hasNext())
{
Character key = new Character(iterator.next());
System.out.println("key : "+key+"value : "+(Integer)hm.get(key));
}
I am getting the following error :
error: constructor Character in class Character cannot be applied to given types;
I have also tried the following way of type casting :
Character key = (Character)iterator.next();
but that would'nt work either. Any help greatly appreciated.
Thanks..
Parametrize your Iterator and use keySet:
Iterator<Character> iterator = hm.keySet().iterator();
Explanation
Iterator is a generic type and should be parametrized. This way, you invoke next without having to cast from Object to your desired type.
Invoking entrySet will return a Set<Entry<Character, Integer>>, which complicates your life unnecessarily if you're iterating the keys
From hm.entrySet() you are trying to get Set<Character,Integer> not Set<Character>
It's better to use keySet(). Because it will return Set<K> (Here Key is Character. So will return Set<Character>):
Set hmset = hm.keySet();
Iterator<Character> iterator = hmset.iterator();
while(iterator.hasNext())
{
Character key = new Character(iterator.next());
System.out.println("key : "+key+"value : "+(Integer)hm.get(key));
}
Try with this code
Iterator it = hm.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
Character key = (Character)entry.getKey();
Integer value = (Integer)entry.getValue();
System.out.println("key : "+key+"value : "+(Integer)hm.get(key));
}
And why are you getting error in this line Character key = new Character(iterator.next());? . You are passing int value into Character Wrapper Class constructor. It will not allow this.
All the wrapper classes have constructors which can be used to create the corresponding Wrapper class objects by passing either a String or a variable of the same data type as that of the type to which the wrapper class corresponds, except for the Character wrapper class whose object cannot be created with a String.
When i 'getValue()' the object, which is of SomeType, from the hash,
i am having to cast it to SomeType. JVM is&isn't seeing it as of type SomeType:
JVM says true to the check whether that objects is instance SomeType.
the method getClass() on that object is returning SomeType as well.
But, when i try to assign that object to a variable x declared as
SomeType x;
i get the error saying
Type mismatch: cannot convert from Object to A.SomeType.
I'm getting around it by casting the object to SomeType and it's OK.
But, is this routine-- why am i having to cast an object-- one that's come to life as SomeType
at the first place, back to SomeType after it spent some time in a HashMap?
//================
ADD: the code.
this one below gives the error. the line w/comment "THIS LINE WORKS" is the one casting and works.
class SomeType {
private int value;
public void setValue (int value) { this.value = value; }
public int getValue () { return this.value; }
}
void doThis(int[] input) {
LinkedHashMap<Integer, SomeType> anElt = new LinkedHashMap<>();
for (Integer key:input) {
SomeType h = new SomeType();
if (anElt.containsKey(key)) {
h = anElt.get(key);
// trimmed off the rest -- nothing relevant here
} else {
h.setValue(key); // ...
}
anElt.put(key, h);
}
Set set = anElt.entrySet();
Set<SomeType> outSet = new LinkedHashSet<SomeType> ();
// Get an iterator
Iterator i = set.iterator();
while(i.hasNext()) {
Map.Entry me = (Map.Entry)i.next();
System.out.print(me.getKey() + ": ");
// SomeType h = (SomeType)(me.getValue()); // THIS LINE WORKS. -- not the one after.
SomeType h = me.getValue();
System.out.println(h.getValue());
}
Java generics allows you to define a collection with the actual type of objects it will be storing. In older version of Java(i belive prior Java5), all collections used to store the raw type objects and hence every time casting was required to the actual object. But using generics you can define your collection with actual types and compiler will not let you put any other type in it. So you can define a HashMap of keys of type String and values of type Integer like this:
Map<String,Integer> myMap = new HashMap<String, Integer>();
further improvement in Java 7 to this concept, now you need not to define the types twice in the declaration, so this is much cleaner way in Java 7 to define the same Map:
Map<String,Integer> myMap = new HashMap<>();
Using generics now you don't have to cast the values to Integer, so this will work:
Integer value = myMap.get("myKey");
you don't have to do this:
Integer value = (Integer)myMap.get("myKey");
If you declare your HashMap without bounded key/value types, you're going to get a raw Object when you query it. This would require you to do an explicit cast to your type (not good)
If you want to take advantage of the polymorphic aspect, you need to bind your types to the declaration:
Map<TypeA, TypeB> map = new HashMap<TypeA, TypeB>();
So your problem is this:
Iterator i = set.iterator();
You need to bind SomeType to your iterator!!!
Iterator<SomeType> i = set.iterator();
Previously I set up an ArrayList to contain objects of records. I have since replaced the ArrayList with a HashMap where the objects are stored and use the username string of an individual as the key.
The class of this directory implemented Iterable through implements Iterable<Object> (just a one off question, but why is <Object> required?).
The previous code used to iterate over the ArrayList was:
public Iterator iterator() {
return records.iterator();
}
I then used this iterator for all objects in that class as follows:
for (Object o : directory) {
TelephoneRecords temp = (TelephoneRecords) o;
System.out.println(temp.toString());
}
Unfortunately, the HashMapName.iterable(); seems to raise issues, so how do I go about this behaviour with a HashMap?
If you're only interested in the keys, you can iterate through the keySet() of the map:
Map<String, Object> map = ...;
for (String key : map.keySet()) {
// ...
}
If you only need the values, use values():
for (Object value : map.values()) {
// ...
}
Finally, if you want both the key and value, use entrySet():
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
// ...
}
Hope this helps you.
You can iterate over the entrySet of the HashMap. The entrySet contains the sets of keys and values. The keys and values are then accessible through getKey() and getValue(). This can be done by the following code:
for (Map.Entry<String, Object> entry : map.entrySet()) {
String username = entry.getKey();
TelephoneRecord record = (TelephoneRecord)entry.getValue();
// Do something with username and record ...
}
Your off-question:
Object is a type parameter for the HashMap, which says that the Iterable contains Objects. If your HashMap is only supposed to contain TelephoneRecords objects, replace
implements Iterable<Object>
with
implements Iterable<TelephoneRecords>
That way you're saying that your Iterable contains TelephoneRecords, which in turn lets you avoid casting and get compile errors instead of runtime errors if you're doing something wrong (which is prefered!). That would improve the above code to:
for (Map.Entry<String, TelephoneRecord> entry : map.entrySet()) {
String username = entry.getKey();
TelephoneRecord record = entry.getValue();
// Do something with username and record ...
}
What does "seems to raise issues" mean? In a HashMap, you can iterate over keys (map.keySet()), values (map.values()) or key-value pairs (map.entrySet()).
I solved my issue with replacing records.iterator(); (which didn't work) with records.values().iterator();. It seems you cannot iterate directly over a HashMap but you can iterate over the values (objects) within it.
Furthermore, the issue of getting and printing the contents of the HashMap, I solved through the following code. It iterates over the TelephoneRecords objects within the directory, as specified by TelephoneRecords o : directory and the Iterator method within the directory class. Then a temporary object is assigned to the TelephoneRecords object being iterated over, and the [custom] toString() method used to print out the string of that specific TelephoneRecords object.
for (TelephoneRecords o : directory) {
TelephoneRecords temp = (TelephoneRecords) o;
System.out.println(temp.toString());
}
And I ended up solving my little side question by following the help provided, using Iterator<TelephoneRecords> (rather than simply using Object) to iterate over the TelephoneRecords objects contained within the directory object.
You can use the entryset from the hashmap, then iterate over that in the same manner as you do already e.g.
for (Object o : Directory.getEntrySet()) {
}
Also, if you type your hashmap it will remove the need for the cast -
Map<String, TelephoneRecords>