I have a Staff class which contains a list of roles for that particular staff member. I also have staffList which holds the staff objects.
How do I get an element from the rolesList for that specific instance of the class?
I have tried:
staffList.get(0).getRolesList().get(0)
Which should be the first element of the rolesList from the first element of the staffList, but it just ruturns null.
I also tried:
rolesList.get(staffList.get(0))
rolesList.getIndexOf(staffList.get(0).getRolesList.get(0)
All return null
If I just get the value direct from the rolesList using get index it will display no problem.
I think it is getting a version of the rolesList but not the one that is in that particular Staff object
I have created a new Staff Member and a role in the roleList then used the list when I construct the staff object, so using the getRolesList method of that object and then get the index it should return the value from within the roleList but it isn't:
private List<Staff> staffList = new ArrayList();
ArrayList<Role> roleList = new ArrayList();
roleList.add(Role.DRIVER);
testDriver = new Staff("Mike", "Joy", roleList);
testStaffList.add(testDriver);
GetRolesList() Code
public List<Role> getRoleList() {
return roleList;
}
I basically want to get the stored Role from the objects rolelist within the testdriver object.
testDriver --> roleList --> Role.DRIVER (or whatever the Role happens to be)
(a) We do not see the line of code adding testDriver to the staffList.
staffList.add( testDriver );
(b) You are missing parens on your call to getRolesList.
(c) You need to do some basic debugging. In the debugger or in extra code, look at:
size of staffList
Staff s = staffList.get(0)
List roles = s.getRolesList()
size of roles
Bonus tip… Apparently you are using an enum for Role. If so, you should consider using an EnumSet rather than a List for less memory usage and faster execution. EnumSet is a specialized implementation of Set. More discussion on another Question. Not part of your problem, just a tip.
Set<Role> roles = EnumSet.of( Role.DRIVER , Role.MECHANIC );
Staff testDriver = new Staff( "Mike" , "Joy" , roles );
Could you give your full source..
That's not clear. I think u wanna add your staff object into staff list.. If it is
Stafflist.add(new Staff("a","b",role list));
Add all you want
Then try to get ..
Related
I have a problem in a Java project.
The code where error born is the following:
HashMap<String, LinkedList<? extends User>> signedUpUsers =
new HashMap<>(Map.of(
"Administrator", new LinkedList<Administrator>(),
"Employee", new LinkedList<Employee>(),
"Customer", new LinkedList<Customer>()));
for (String userName : userNameList)
{
userPropertyValue = usersProperties.getProperty(userName).split(",");
String password = userPropertyValue[0].replaceAll("\\s", "");
String role = userPropertyValue[1].replaceAll("\\s", "");
if (role.equals("Administrator"))
{
signedUpUsers.get("Administrator").add(new Administrator(userName, password));
}
else if (role.equals("Customer"))
{
signedUpUsers.get("Customer").add(new Customer(userName, password));
}
else
{
signedUpUsers.get("Employee").add(new Employee(userName, password));
}
}
It gives me an error when I try to add new elements in each list of hashmap, when I create instances, intellij tells me:
Required type: capture of ? extends User
Provided: Customer (or Employee or Administrator)
But why, if Customer, Employee and Administrator are all subclasses of User?
What I should change? My intention is to have an HashMap which contains all signed up users (I saved them in a .properties file which is corrected red because I saw that), where keys are roles of users (Administrators, Employees and Customers), and the value of each key is a LinkedList of each user with that role.
I also tried to use super instead of extends, but in that case I solve this error, but a new error appear in creating the hashmap with Map.of() (because Administrator, Customer and Employee aren't superclass of User).
The code works if I have 3 different lists declared directly with 3 roles objects, but I wanted the hashmap because I want to return the whole signed up users divided by their role.
Thanks to all, I hope I was clear in explaining.
The reason for the compiler error has been covered in #Thomas's comment: To the compiler, signedUpUsers.get("Administrator") is a LinkedList<? extends User>, not knowing that under the "Administrator" key, you stored a LinkedList<Administrator> (and not e.g. a LinkedList<Employee>, so the compiler does not allow adding an Administrator.
Your signedUpUsers variable shows some significant generics over-engineering. You declare
HashMap<String, LinkedList<? extends User>> signedUpUsers =
new HashMap<>(Map.of(
"Administrator", new LinkedList<Administrator>(),
"Employee", new LinkedList<Employee>(),
"Customer", new LinkedList<Customer>()));
I suggest to change that to
HashMap<String, LinkedList<User>> signedUpUsers =
new HashMap<>(Map.of(
"Administrator", new LinkedList<User>(),
"Employee", new LinkedList<User>(),
"Customer", new LinkedList<User>()));
You might ask "But now I don't have the type safety that I can only store Administrator instances under the "Administrator" key." But that type safety also wasn't possible with the first version (at run-time, the LinkedList<Administrator> is just a LinkedList and will happily accept any Object, and at compile-time LinkedList<? extends User> will not allow adding anything).
If you want type safety for the lists, throw away the Map approach, and create a class UserList:
public class UserList {
private List<Administrator> administrators;
private List<Employee> employees;
private List<Customer> customers;
// add constructor, getters, adders etc. here
}
This will easily give the desired type safety.
I have a bunch of objects stored in hashMap<Long,Person> i need to find the person object with a specific attribute without knowing its ID.
for example the person class:
public person{
long id;
String firstName;
String lastName;
String userName;
String password;
String address;
..
(around 7-10 attributes in total)
}
lets say i want to find the object with username = "mike". Is there any method to find it without actually iterating on the whole hash map like this :
for (Map.Entry<Long,Person> entry : map.entrySet()) {
if(entry.getValue().getUserName().equalsIgnoreCase("mike"));
the answers i found here was pretty old.
If you want speed and are always looking for one specific attribute, your best bet is to create another 'cache' hash-map keyed with that attribute.
The memory taken up will be insignificant for less than a million entries and the hash-map lookup will be much much faster than any other solution.
Alternatively you could put all search attributes into a single map (ie. names, and ids). Prefix the keys with something unique if you're concerned with collisions. Something like:
String ID_PREFIX = "^!^ID^!^";
String USERNAME_PREFIX = "^!^USERNAME^!^";
String FIRSTNAME_PREFIX = "^!^FIRSTNAME^!^";
Map<String,Person> personMap = new HashMap<String,Person>();
//add a person
void addPersonToMap(Person person)
{
personMap.put(ID_PREFIX+person.id, person);
personMap.put(USERNAME_PREFIX+person.username, person);
personMap.put(FIRSTNAME_PREFIX+person.firstname, person);
}
//search person
Person findPersonByID(long id)
{
return personMap.get(ID_PREFIX+id);
}
Person findPersonByUsername(String username)
{
return personMap.get(USERNAME_PREFIX+username);
}
//or a more generic version:
//Person foundPerson = findPersonByAttribute(FIRSTNAME_PREFIX, "mike");
Person findPersonByAttribute(String attr, String attr_value)
{
return personMap.get(attr+attr_value);
}
The above assumes that each attribute is unique amongst all the Persons. This might be true for ID and username, but the question specifies firstname=mike which is unlikely to be unique.
In that case you want to abstract with a list, so it would be more like this:
Map<String,List<Person>> personMap = new HashMap<String,List<Person>>();
//add a person
void addPersonToMap(Person person)
{
insertPersonIntoMap(ID_PREFIX+person.id, person);
insertPersonIntoMap(USERNAME_PREFIX+person.username, person);
insertPersonIntoMap(FIRSTNAME_PREFIX+person.firstname, person);
}
//note that List contains no duplicates, so can be called multiple times for the same person.
void insertPersonIntoMap(String key, Person person)
{
List<Person> personsList = personMap.get(key);
if(personsList==null)
personsList = new ArrayList<Person>();
personsList.add(person);
personMap.put(key,personsList);
}
//we know id is unique, so we can just get the only person in the list
Person findPersonByID(long id)
{
List<Person> personList = personMap.get(ID_PREFIX+id);
if(personList!=null)
return personList.get(0);
return null;
}
//get list of persons with firstname
List<Person> findPersonsByFirstName(String firstname)
{
return personMap.get(FIRSTNAME_PREFIX+firstname);
}
At that point you're really getting into a grab-bag design but still very efficient if you're not expecting millions of entries.
The best performance-wise method I can think of is to have another HashMap, with the key being the attribute you want to search for, and the value being a list of objects.
For your example this would be HashMap<String, List<Person>>, with the key being the username. The downside is that you have to maintain two maps.
Note: I've used a List<Person> as the value because we cannot guarantee that username is unique among all users. The same applies for any other field.
For example, to add a Person to this new map you could do:
Map<String, List<Person>> peopleByUsername = new HashMap<>();
// ...
Person p = ...;
peopleByUsername.computeIfAbsent(
p.getUsername(),
k -> new ArrayList<>())
.add(p);
Then, to return all people whose username is i.e. joesmith:
List<Person> matching = peopleByUsername.get("joesmith");
Getting one or a few entries from a volatile map
If the map you're operating on can change often and you only want to get a few entries then iterating over the map's entries is ok since you'd need space and time to build other structures or sort the data as well.
Getting many entries from a volatile map
If you need to get many entries from that map you might get better performance by either sorting the entries first (e.g. build a list and sort that) and then using binary search. Alternatively you could build an intermediate map that uses the attribute(s) you need to search for as its key.
Note, however, that both approaches at least need time so this only yields better performance when you're looking for many entries.
Getting entries multiple times from a "persistent" map
If your map and its valuies doesn't change (or not that often) you could maintain a map attribute -> person. This would mean some effort for the initial setup and updating the additional map (unless your data doesn't change) as well as some memory overhead but speeds up lookups tremendously later on. This is a worthwhile approach when you'd do very little "writes" compared to how often you do lookups and if you can spare the memory overhead (depends on how big those maps would be and how much memory you have to spare).
Consider one hashmap per alternate key.
This will have "high" setup cost,
but will result in quick retrieval by alternate key.
Setup the hashmap using the Long key value.
Run through the hashmap Person objects and create a second hashmap (HashMap<String, Person>) for which username is the key.
Perhaps, fill both hashmaps at the same time.
In your case,
you will end up with something like HashMap<Long, Person> idKeyedMap and HashMap<String, Person> usernameKeyedMap.
You can also put all the key values in the same map,
if you define the map as Map<Object, Person>.
Then,
when you add the
(id, person) pair,
you need to also add the (username, person) pair.
Caveat, this is not a great technique.
What is the best way to solve the problem?
There are many ways to tackle this as you can see in the answers and comments.
How is the Map is being used (and perhaps how it is created). If the Map is built from a select statement with the long id value from a column from a table we might think we should use HashMap<Long, Person>.
Another way to look at the problem is to consider usernames should also be unique (i.e. no two persons should ever share the same username). So instead create the map as a HashMap<String, Person>. With username as the key and the Person object as the value.
Using the latter:
Map<String, Person> users = new HashMap<>();
users = retrieveUsersFromDatabase(); // perform db select and build map
String username = "mike";
users.get(username).
This will be the fastest way to retrieve the object you want to find in a Map containing Person objects as its values.
You can simply convert Hashmap to List using:
List list = new ArrayList(map.values());
Now, you can iterate through the list object easily. This way you can search Hashmap values on any property of Person class not just limiting to firstname.
Only downside is you will end up creating a list object. But using stream api you can further improve code to convert Hashmap to list and iterate in single operation saving space and improved performance with parallel streams.
Sorting and finding of value object can be done by designing and using an appropriate Comparator class.
Comparator Class : Designing a Comparator with respect to a specific attribute can be done as follows:
class UserComparator implements Comparator<Person>{
#Override
public int compare(Person p1, Person p2) {
return p1.userName.compareTo(p2.userName);
}
}
Usage : Comparator designed above can be used as follows:
HashMap<Long, Person> personMap = new HashMap<Long, Person>();
.
.
.
ArrayList<Person> pAL = new ArrayList<Person>(personMap.values()); //create list of values
Collections.sort(pAL,new UserComparator()); // sort the list using comparator
Person p = new Person(); // create a dummy object
p.userName="mike"; // Only set the username
int i= Collections.binarySearch(pAL,p,new UserComparator()); // search the list using comparator
if(i>=0){
Person p1 = pAL.get(Collections.binarySearch(pAL,p,new UserComparator())); //Obtain object if username is present
}else{
System.out.println("Insertion point: "+ i); // Returns a negative value if username is not present
}
I have this code where the ArrayList was instantiated outside any condition:
List<PatientDto> list = new ArrayList<PatientDto>();
for(Object o : ObjectList){
if(true){
PatientDto patient = new PatientDto(....);
list.add(patient);
}
}
PatientDto dto = list.get(0);
Will I still be able to retrieve the new PatientDto() as I access the list, given that it was instantiated within the if statements?
yes
Patient is inside the scope of your if clause but it can be accessed outside the block if you have access to the reference for the same outside the if clause.
The list has stored a reference of your patient object which will be accessible whereever you can access the list. Hence, you can access your contained object by fetching it from the list.
Yes, since you are inserting it in to the list, you can get it by using index. Or you can iterate after insertion of all the objects later.
for ex:
PatientDto patient = list.get(index);
update :
PatientDto dto = list.get(0);
Yes, that gives the 0th indexed PatientDto from the list, which whatever you put earlier in that place. Since you adding new instances in the loop, they give you the same.
coming to the scope
for(Object o : ObjectList){
if(true){
PatientDto patient = new PatientDto(....);
list.add(patient);
}
}
System.out.println(patient); // err, I dont know what is patient
System.out.println(list.get(0)) // yay here is the patient, use it.
I am throwing a ConcurrentModificationExample in the following code. I checked the API and it has to do with me trying to modify an object while another thread is iterating over it. I am clueless on the matter. I have created a comment above the line causing the exception. The Employee class doesn't contain anything other than the three variables for storing information.
I will be including the entire class as I would also like to know if there is a way to simplify my code as it repeats many things such as object creation and adding everything to the lists.
When you call employeesByAge in here with dep.employees:
dep.employeesByAge(dep.employees)
that will pass in dep.employees to employeesByAge such that in:
public class Department{
LinkedList<Employee> employees = ...;
public LinkedList<Employee> employeesByAge(LinkedList<Employee> outputList) {
...
}
}
both the employee member field and the outputList parameter refers to the same list, not just two list with the same content, but the same list instance.
Then you do:
for (Employee emp: employees){
//the list is null. add the first employee
if (outputList.isEmpty()){
outputList.add(emp);
} else
...
}
which iterates the employee and modifies outputList, but remember that these two are the same list object. Thus, ConcurrentModificationException.
What you're attempting to do is similar to this...
List list = ...;
for(item: list) {
list.add(item);
}
That is, you're updating a collection with elements by iterating over the same collection. All
outputList.add(...);
in Department are adding elements to the collection from the same collection 'employees'.
In main(), by doing
dep.employeesByAge(dep.employees)
you're attempting to update 'dep.employees' with 'dep.employees.' which results in concurrent modification exception.
there is a dependent list
Dependents contains
String emp_Id, name etc,
List<Dependent> dependentList;
dependentList contains all the dependent information of an employee.
how to get the list of dependents by providing the emp_Id ?
for example an employee will have 2 or 3 dependents.
ok i dont want to loop over it.
i tried binary search on list using comparator but it does not return the desired data.
already i will loop over the employee list... subsequently i should get the depends of the particular employee...
what will be the best & efficient solution ?
Binary search works only if the list is sorted according to the comparator. For lists that are not sorted or sorted according to other criteria, you have to filter them.
Either loop though the list and do whatever you want to do in the loop body
Or use a filter functionality from a library
If you want to filter, then I recommend Google Collections (or Google Guava, which is a superset of Google collections):
Collection<Dependent> filtered = Collections2.filter(dependentList, new Predicate<Dependent>() {
public boolean apply(Dependent from) {
return from != null && from.getId().equals(id_so_search_for);
}
}
Of course, you are not restricted to .equals(), but can match according to any operation required (e.g. by regular expression).
If searches for one kind of data heavily outweight searches for any other kind of data, then storing them in a Map<kind-of-id, Dependent> may be a good choice as well. You still can retrieve a collection of all stored objects using Map.values().
If one key maps to several items, then either use a Map<kind-of-id, Collection<Dependent>> or (better) consider using existing Multimap functionality: com.google.common.collect.Multimap or org.apache.commons.collections.MultiMap (note that Apache Commons does not have a genericized version of this).
You want to model relationships. I guess, you have the basic dependencies:
Supervisor is-a Employee
Supervisor has-many Employees (Dependants in your case)
So a very basic implementatin could go like this:
public class Employee {
int emp_id;
// more fields, more methods
}
public class Supervisor extends Employee {
private List<Employee> dependants = new ArrayList<Employee>();
// more fields, more methods
public List<Employee> getDependants() {
return dependants;
}
}
public class StaffDirectory {
private Map<Integer, Employee> staff = new HashMap<Integer, Employee>();
public static List<Employee> getAllDependantsOf(int employeeId) {
Employee employee = staff.get(employeeId);
if (employee instanceof Supervisor) {
return ((Supervisor) employee).getDependants());
} else {
return Collections.emptyList();
}
}
}
What have you tried so far? Do you have anything written?
Here is a general guess:
int employeeToFind = 10;//the id to search for
for(Dependant dep : dependentList ) {
if(dep.getEmployeeId() == employeeToFind) {
//do something
}
}
You could also store dependents in a Hashtable<Integer employeeId,List<Dependent>>(); keyed by EmployeeId for an easy lookup.
As alzoid mentioned, a HashMap or HashTable is the perfect data structure for this task. If you have any chance to load your instances of Dependent into such an object, do so.
Still, have this delicious code:
String emp_Id //IDs are usually integer, but I'll go with your example
List<Dependent> dependentList; //assume this is populated
List<Dependent> desiredSublist = new ArrayList<Dependent>();
for(Dependent dep:dependentList){
//make sure to compare with equals in case of Id being String or Integer
if(dep.getId().equals(emp_Id)){
desiredSubList.add(dep);
}
}
//desiredSublist now contains all instances of Dependent that belong to emp_Id.