I have created a Map as follows:
private Map<String, List<Client>> clientCatalogue;
this.clientCatalogue = new TreeMap<String, List<Client>>();
The keys are client names, and the values are a list of client details.
I am iterating over it using keySet(). I want to access each list of values associated with the keys one at a time, and then do further processing on each before moving on to the next list of values. I have copied the values into a List type variable (clientDetails) and thought I'd print them out to check them. But I keep getting hashcodes back. Why is this, and what can I do to unpack these hashcodes and access the values I want? Any suggestions appreciated.
List<Client> clientDetails;
clientDetails = new ArrayList<Client>();
for (String eachClient : this.clientCatalogue.keySet())
{
clientDetails = clientCatalogue.get(eachClient);
System.out.println("Details of client are: " + clientDetails);
}
Try this:
for (String eachClient : this.clientCatalogue.keySet())
{
List<Client> clientDetails; = clientCatalogue.get(eachClient);
for(Client cl : clientDetails)
{
System.out.println("Details of client are: " + cl.toString());
}
}
The problem was that you were printing the list as a whole instead of the individual clients in the list.
BTW, you need a proper implementation for the toString() method in your Client class.
Also you do not need to create a new instance for List<Clients> clientDetails.
Also, if you do not want to iterate on the keys but on the values directly do this:
for (List<Client> clientDetails : this.clientCatalogue.values())
{
for(Client cl : clientDetails)
{
System.out.println("Details of client are: " + cl.toString());
}
}
You should override toString() method in Client class. When you try to print any object through sysout then its toString method will be called, In your case its called of the Object's class. So override it as how you want sysout print it for you.
You need to implement toString() in your Client class to return the details you want to see printed.
TreeMap inherits it's toString method from AbstractMap which it looks like will attempt to output a pretty representation of the map, but if you haven't given a toString implementation of clientDetails you aren't going to get anything pretty. A sample of your string output would help to know for sure though.
Related
I am trying to replace element in collection with new modified version. Below is short code that aims to demonstrate what I'd like to achieve.
The whole idea is that I have one object that consists of collections of other objects. At some point in time I am expecting that this objects in collections (in my example phones) might require some modifications and I'd like to modify the code in one place only.
I know that in order to update the object's attributes I can use setters while iterating through the collection as demonstrated below. But maybe there is better, more general way to achieve that.
public class Customer {
private int id;
private Collection<Phone> phoneCollection;
public Customer() {
phoneCollection = new ArrayList<>();
}
//getters and setters
}
and Phone class
public class Phone {
private int id;
private String number;
private String name;
//getters and setters
}
and
public static void main(String[] args) {
Customer c = new Customer();
c.addPhone(new Phone(1, "12345", "aaa"));
c.addPhone(new Phone(2, "34567", "bbb"));
System.out.println(c);
Phone p = new Phone(2, "9999999", "new name");
Collection<Phone> col = c.getPhoneCollection();
for (Phone phone : col) {
if (phone.getId() == p.getId()) {
// This is working fine
// phone.setNumber(p.getNumber());
// phone.setName(p.getName());
// But I'd like to replace whole object if possible and this is not working, at least not that way
phone = p;
}
}
System.out.println(c);
}
}
Is this possible to achieve what I want?
I tried copy constructor idea and other methods I found searching the net but none of them was working like I would expect.
EDIT 1
After reading some comments I got an idea
I added the following method to my Phone class
public static void replace(Phone org, Phone dst){
org.setName(dst.getName());
org.setNumber(dst.getNumber());
}
and now my foreach part looks like that
for (Phone phone : col) {
if (phone.getId() == p.getId()) {
Phone.replace(phone, p);
}
}
And it does the job.
Now if I change the Phone class attributes I only need to change that method. Do you think it is OK solving the issue that way?
You should not modify the collection while you're iterating through it; that's likely to earn you a ConcurrentModificationException. You can scan the collection for the first object that matches your search criterion. Then you can exit the loop, remove the old object, and add the new one.
Collection<Phone> col = c.getPhoneCollection();
Phone original = null;
for (Phone phone : col) {
if (phone.getId() == p.getId()) {
original = phone;
break;
}
}
if (original != null) {
Phone replacement = new Phone(original);
replacement.setNumber(p.getNumber());
replacement.setName(p.getName());
col.remove(original);
col.add(replacement);
}
Alternatively, you could declare a more specific type of collection, such as a List, that would allow you to work with indexes, which would make the replacement step much more efficient.
If your phone IDs are unique to each phone, you should consider using a Map<Integer, Phone> that maps each phone ID to the corresponding phone. (Alternatively, you could use some sort of third-party sparse array structure that doesn't involve boxing each ID into an Integer.) Of course, if your IDs aren't unique, then you might want to modify the above to gather a secondary collection of all matching phones (and reconsider the logic of your existing code as well).
You can also use a Set (HashSet), this is only when you don't want to do the way Mike suggested.
Use the Phone as an item in the set. Don't forget to implement hashCode() and equals() in Phone. hashCode() should return the id, as it is supposed to be unique.
Since you are concerned about replacing the item, here's how HashSet will help you :
Create an instance of your object.
Remove the object you want to replace from the set.
Add the new object (you created in step 1) back to the set.
Both these operations 2 & 3 are guaranteed in O(1) / constant time.
You don't need to maintain a map for this problem, that's redundant.
If you want to get the object from the collection itself and then modify it, then HashMap would be better, search is guaranteed in O(1) time.
Instead of a list, use a map with the Phone's id as the key. Then your code looks like this:
public static void main(String[] args) {
Customer c = new Customer();
c.addPhone(new Phone(1, "12345", "aaa"));
c.addPhone(new Phone(2, "34567", "bbb"));
System.out.println(c);
Phone p = new Phone(2, "9999999", "new name");
Map<Integer, Phone> phoneMap = c.getPhoneMap();
phoneMap.put(p.getId(), p);
System.out.println(c);
}
If you take the object out from the collection and update its properties, it will get reflected in the same object in collection too.. Hence, you dont have to technically replace object after updating it.
As "Mike M." pointed out, you can use hashmap to retrieve the object quickly without iteration and update the object values.
If order matters to you, you can change Collection to List (Since you're always using an ArrayList anyway) and then:
int index = col.indexOf(phone);
col.remove(phone);
col.add(p, index);
so I have been able to put objects into my hash map successfully, but I'm having trouble returning an object. When I used an arrayList for this same project, I simply displayed it with the following method:
public void displayDetails(int currentItem) {
accountIDTextField.setText(table.get(currentItem).getAccountID()+"");
accountNumberTextField.setText(table.get(currentItem).getAccountNumber());
surnameTextField.setText(table.get(currentItem).getSurname());
accountTypeTextField.setText(table.get(currentItem).getAccountType());
}
And pressing the 'first' button would go to the number 1 in the list.
first.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
currentItem = 1;
displayDetails(currentItem);
}
});
As for my hashing, I have used the accountNumber as the key, (hashed by using the % modulo function)
Working backwards, I can get the accountID when I pass in the accountNumber as a parameter in the get() method.
hashMap.get(12345678).getAccountID();
But how do I return the accountID if I just want to get the first object stored in the hash map(i.e get accountID without knowing accountNumber)?
(AccountID is an integer unique to a particular account and will be automatically generated when a new account record is created)
Sorry if this isn't worded very well, I'm still trying to get my head around Java and OOP in general. Any help would be greatly appreciated. Thanks
hope I understood you right. getting only the first item of a HashMap would be something like:
Map<String, String> myhashmap = new HashMap<String, String>();
myhashmap.entrySet().iterator().next();
You can get the contents of the Map by using Map.values().
I would't access the value based on it's order in the map because ordering is not guaranteed. You should give each one a defined number. Then you can access them like:
Object o = map.values().get(id);
to get the first:
Object o = map.values().get(0);
For the following class I want to access an object if the name equals to something, let's say "you". Otherwise I want to create it.
I want to check if an object exists that has the name as 'you' and then add entries to the ArrayList contInstances. If such an instance doesn't already exist I want to create it. Next time I might have to use the same object so that I can add some more entries to the ArrayList.
public class Values {
String name;
ArrayList<anotherClass> classInstances = new ArrayList<anotherClass>();
}
This happens to be in a loop. How can I do that?
Edit: I'll quote an example here:
if (an object exists that contains field 'name' == 'YOU'){
add entries to the array list directly using the available object
}
else {
create a new object and set the 'name' = 'YOU';
add entries to the array list;
}
It sounds kind of like you want to have a cache by name. Instead of an ArrayList, consider using a Map<String, AnotherClass> to keep track of Name->Object mappings.
You can then use this approach:
Map<String, AnotherClass> instances = new LinkedHashMap<String, AnotherClass>();
for (...) {
String name = getNextName();
AnotherClass instance = instances.get(name);
if (instance == null) {
instance = makeInstance(name);
instances.put(name, instance);
}
useInstance(name, instance);
}
After that loop is finished, if you still want a List<AnotherClass>, you can use return new ArrayList<AnotherClass>(instances.values());
I have a requirement where i have to print the values which are getting saved in a database. I have pojo object which i am passing it in a list and then saving the entire list in database. Please find the below code.
List dataList=new ArrayList();
Vehicles vehiclePojoObject=new Vehicles();
vehiclePojoObject.setName("Cycle");
vehiclePojoObject.setColor("Blue");
dataList.add(vehiclePojoObject);
Now i have to print the values which is contained by vehiclePojoObject. How can it be acheived. Please guide. Thanks in advance.
Note: There are not one object but multiple objects which are getting stored in the list.
Other than the solution posted by #McMonster, you could also make sure that your POJO's override the toString() method so that you can print a customized, and most likely, more readable string representation of your object.
Add vehiclePojoObject to the Vehicles List object, like
List<Vehicles> vehList = new ArrayList<Vehicles>();
Vehicles vehiclePojoObject=new Vehicles();
vehiclePojoObject.setName("Cycle");
vehiclePojoObject.setColor("Blue");
vehList.add(vehiclePojoObject); //Here we are adding pojoObject to list object
And get Vehicles List data through for-each
i.e.
for(Vehicles vehicle : vehList){
System.out.println("Vehicle Name: "+veh.getName());
System.out.println("Vehicle Color: "+veh.getColor());
}
Expanding on #npinti answer of overriding toString()
In your POJO file, add this function:
#Override
public String toString() {
String output = "Name: " + getName() + " Color: " + getColor +
" Model: " + getModel() + ....;
return output;
}
then you can loop through your list to and call .toString() on all the objects to print out all of the features
for(Vehicles vehicle : vehList){
System.out.println(vehicle.toString());
}
Assuming that you want to store objects of different types on the same list and have a single method for printing all private fields of those object regardless of their types you can use the (reflection API).
By the help of reflection we can change behavior of list at runtime
List dataList = new ArrayList<>();
// Print the name from the list....
for(Vehicles vehicle: Vehicles) {
System.out.println(vehicle.getName());
System.out.println(vehicle.getColor());
}
Hope this helps!!!
I am having difficulty accessing some data. I am using YCSB to talk to a number of different databases, such as Cassandra and MongoDB.
The only class I can really modify is my "Workload" class, which is doing some insertions and reads. The method I am using to read from the database is in the class:
public void doRead(DB db)
{
String keyname = buildKeyName(keynum);
System.out.println(keyname);
HashSet<String> fields = null;
if (!readallfields)
{
// read a random field
String fieldname = "field" + fieldchooser.nextString();
fields = new HashSet<String>();
fields.add(fieldname);
}
db.read(table,keyname,fields,new HashMap<String,ByteIterator>());
}
I tried to modify the code so I could read the contents of the hashmap. I removed the db.read line and replaced it with
HashMap<String, ByteIterator> kv_hashmap = new HashMap<String, ByteIterator>();
db.read(table, keyname, fields, kv_hashmap);
Then tried to read from kv_hashmap:
System.out.println(kv_hashmap.get(fields));
BUT db.read returns only an int. DB is a public abstract class which I would rather not modify and its purpose is to talk to a variety of databases:
This is what db.read calls:
public abstract int read(String table, String key, Set<String> fields, HashMap<String,ByteIterator> result);
Which returns, to quote from the javadoc:
Zero on success, a non-zero error code on error or "not found".
I need to read the values from kv_hashmap. I don't understand why I can't access its values.
I took a look at the implementation of the DB class and the javadoc additionally says:
#param result A HashMap of field/value pairs for the result
But, I then also looked at BasicDB which extends DB - and its body simply prints out the fields passed in.
What I suggest you do is print the actual concrete class of DB being passed into your method and see what that class is actually doing inside the read method, something like:
System.out.println(Test.class.getName());
Then take a look at the read method of whatever class is shown - if its not populating the result HashMap (as with the BasicDB implementation) then there wont be anything for you to read