ConcurrentModificationExample and possible code simplification - java

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.

Related

.map and mutation of original object's content

Consider this code
List<Employee> employees = new ArrayList<Employee>();
employees.add(new Employee("A", "B"));
employees.add(new Employee("A1", "B1"));
employees.stream().map(e-> { e.setfName("Mr. " + e.getfName()); return e; }); // 1. DOES NOT mutate employees' content
employees.stream().map(e-> { e.setfName("Mr. " + e.getfName()); return e; }).collect(Collectors.toList()); // 2. DOES mutate employees' content
employees.stream().map(e-> new Employee ("Mrs. " + e.getfName(), e.getlName())).collect(Collectors.toList()); // 3. DOES NOT put new objects in original list
Not sure if I understand the reason for this behavior. If the stream does create a separate memory, shouldn't 2 also NOT mutate the original list's content?
employees.stream().map(e-> { e.setfName("Mr. " + e.getfName()); return e; }); // 1. DOES NOT mutate employees' content
Line 1 only doesn't mutate employees' content because it doesn't do anything at all. Streams aren't evaluated until a terminal operation is called.
Line 2 creates a new list to hold the updated employees, but the original employees are updated -- so you have two independently modifiable lists that contain exactly the same employees with exactly the same data where you can't modify one without the other. So with the result of line 2, you could add new Employee objects and not modify employees, but you couldn't modify the employees in that List without modifying the originals too (because they're the same employees).
Only Line 3 creates new Employee objects which exist independently of the originals.
An important thing to understand about streams is that they are lazy. If you map the values, the mapping function is only called when you retrieve values from the stream. collecting a stream is one way to use the values and force the mutations, which is why the second example mutates the list and the first one doesn't. The third example doesn't mutate the objects in place, instead creating a new Employee for each one, so it creates a new cloned list that is unrelated to the original list.

Java - adding new Object within an if() statement to a list declared outside if(){}

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.

Multiple calls to a void method using list parameter as return value is better than a method that return a List?

In short, my question is: If a method is called multiple times, is it better in terms of memory consumption to make it void and use a List as parameter to return its values? In case it really saves memory, isn't it a bad practice as the code is harder to read?
Let me provide an example to make it clearer. Suppose I have a class Car and each car must belong to a brand. I have a method that returns all the cars from a list of brands and this method uses a foreach and a method that retrieves all the cars from one brand. Like the following code:
private List<Car> getCarsByBrands(List<Brand> brands) {
List<Car> result = new Arraylist<>;
for(Brand brand : brands) {
result.add(getCarsBySingleBrand(brand))
}
return result;
}
private List<Car> getCarsBySingleBrand(Brand brand) {
List<Car> result = new Arraylist<>;
result.add(retrieveCarsByBrand(brand)) // retrieveCarsByBrand omitted
return result;
}
A colleague of mine defends that the method getCarsBySingleBrand should be rewritten to be void and use a List as parameter and this list would contain all the cars as you can see below:
private List<Car> getCarsByBrands(List<Brand> brands) {
List<Car> result = new Arraylist<>;
for(Brand brand : brands) {
getCarsBySingleBrand(result, brand))
}
return result;
}
private void getCarsBySingleBrand(List<Car> cars, Brand brand) {
cars.add(retrieveCarsByBrand(brand)) // retrieveCarsByBrand omitted
}
He argues that this way it consumes less memory, because he does not create a List everytime the method getCarsBySingleBrand is called. I think this is a kind of unnecessary optimization and is a bad practice because the code is harder to understand.
The second option MIGHT be more optimal.
The issue is the first way not only has to make another List object for every brand, which is then just thrown away but if there are a lot of cars for a brand, then Java will resize the list (which is initialized to the default size of 16) many times. The resizing operation requires copying the array. This could get expensive if you resize many times.
The second option only has one list and since resizing usually doubles the capacity, it should have to resize fewer times than the first option.
However, this is getting into micro-optimizations. I wouldn't worry about this kind of thing unless you are noticing a performance issue and have done analysis to determine that this is a bottleneck.
If you are worried about the method name, I think having the word "get" in the name is throwing you off because it usually implies returning something. Naming it something like addBrandOfCarsTo() might make it read more like a sentence:
for(Brand brand : brands) {
addBrandOfCarsTo(result, brand));
}
Both options are good, and depend mostly of your preferences:
some preople prefer clarity (and each people have his own style).
others prefer preformance, however small it.
If your case you could also call directly to retrieveCarsByBrand and uses its result:
private List<Car> getCarsByBrands(List<Brand> brands) {
List<Car> result = new Arraylist<>;
for(Brand brand : brands) {
result.add(retrieveCarsByBrand(brand))
}
return result;
}
Or simplify getCarsBySingleBrand and uses its result:
private List<Car> getCarsByBrands(List<Brand> brands) {
List<Car> result = new Arraylist<>;
for(Brand brand : brands) {
result.add(retrieveCarsByBrand(brand));
}
return result;
}
private List<Car> getCarsBySingleBrand(Brand brand) {
return retrieveCarsByBrand(brand);
}
or do a compromise between clarity and performance changing the name of getCarsBySingleBrand:
private List<Car> getCarsByBrands(List<Brand> brands) {
List<Car> result = new Arraylist<>;
for(Brand brand : brands) {
getCarsBySingleBrand(result, brand))
}
return result;
}
private void addBrandCars(List<Car> cars, Brand brand) {
cars.add(retrieveCarsByBrand(brand)) // retrieveCarsByBrand omitted
}
I guess you can use both worlds.
The only advantage in the second one is it consumes less memory. Making a functional method instead a void one will increase clarity, as said before, and will help in unit testing (you can mock the returned value).
Here is how I would do it:
private List<Car> getCarsByBrands(List<Brand> brands) {
List<Car> result = new Arraylist<>;
for(Brand brand : brands) {
getCarsBySingleBrand(result, brand))
}
return result;
}
private List<Car> addBrandCars(List<Car> cars, Brand brand) {
cars.add(retrieveCarsByBrand(brand)) // retrieveCarsByBrand omitted
return cars;
}
He is might be correct.
Let's explain WHY.
so in first example for each brand you are creating new list in getCarsBySingleBrand method and than you have to add cars from newly created list in result list being in getCarsByBrands.
result.add(getCarsBySingleBrand(brand))
in this line you just get list from getCarsBySingleBrand and add all those elements to result.
But in second case you add cars directly to getCarsByBrands list , so you do less operations.
Also It's correct to say that first example consumes slightly more memory. But I think more problem here is just operations , not memory.
Conclusion:
In my opinion second method is not really a bad style. So you can make such optimizations if it's needed.
As #dkatzel said, the second option might be better. But that's only because in the first option, in method getCarsBySingleBrand(Brand brand), you are unnecessarily copying retrieveCarsByBrand(brand) result to a fresh new ArrayList. This means that 3 different lists exist before the method getCarsBySingleBrand(Brand brand) returns:
The one that holds the final result
The sublist with the cars of one single brand, returned by retrieveCarsByBrand(brand)
The new ArrayList you're using to copy the list returned by retrieveCarsByBrand(brand)
If, as suggested by #Narkha, in the first option, you simplified the method getCarsBySingleBrand(brand) by not copying the list of cars returned by retrieveCarsByBrand(brand) to a new ArrayList, or by just inlining retrieveCarsByBrand(brand) method, then both options would be the same, in terms of memory consumption. This is because in both approaches, the list of cars retrieved for a single brand would be copied to the list that holds the final result once per brand. This means that only 2 lists would exist at the same time:
The one that holds the final result
The sublist with the cars of one single brand, returned by retrieveCarsByBrand(brand)
As stated by others, this kind of optimization is hardly ever needed. However, you should know there's a more optimal way to do this, if you use Guava (you should!).
private Iterable<Car> getCarsByBrands(List<Brand> brands) {
Iterable<Iterable<Car>> carsGroupedByBrand = new Arraylist<>();
for(Brand brand : brands) {
carsGroupedByBrand.add(retrieveCarsByBrand(brand));
}
return Iterables.concat(carsGroupedByBrand);
}
This solution stores a list of sublists of cars, where each sublist holds the cars of each brand, and at the end decorates the list of sublists of cars into a single Iterable of cars. If you really, really need to return a List instead of an Iterable, then you could modify the last line as follows:
return Lists.newArrayList(Iterables.concat(carsGroupedByBrand));
The key word here is decorates, meaning no actual copy of any sublist is performed. Instead, a special-purpose iterator is created, which traverses every element of the first sublist, and when it reaches its end, it automatically and transparently 'jumps' to the first element of the second sublist, until it reaches its end, and so on, until it reaches the last element of the last sublist. Please refer to Guava's Iterables.concat(...) method documentation for further details.

how to add a list to another list while looping?

I have a list which has object(record) taken from database. I need to add it another list of generic class inside a loop.When ever loop executes the final list contains only the last element.my coding are..
List<modelclass> mdlclasslist=new ArrayList();
for(Class_1 a:class1list) {
Query qr=s.createQuery("from Class_2 where ID= :f and code= :j order by mark desc");
qr.setParameter("f",id);
qr.setParameter("j",code);
List<Class_2> b=new ArrayList();
b=qr.list();
for(Class_2 cls:b) {
modelclass mdl=new modelclass(cls.getID(),cls.getCode(),cls.getMark());
mdlclasslist.add(mdl);
}
}
mdlclasslist contains same object.It is not adding every object the query takes.please advice.
Your Query appears to return the same list over and over again for every Class_1 item because id and code never change. I assuming your code should rather look like this:
Query qr=s.createQuery("from Class_2 where ID= :f and code= :j order by mark desc");
for( Class_1 a : class1list )
{
qr.setParameter( "f", a.id );
qr.setParameter( "j", a.code );
for( Class_2 cls: qr.list() )
{
modelclass mdl=new modelclass(cls.getID(),cls.getCode(),cls.getMark());
mdlclasslist.add(mdl);
}
}
How about debugging and printing out the number of elements in the 2nd list before adding?
Not sure if you want to append the List you retrieve from a DB to the one you initialize beforehand...
However, I would define the 1st List to be of the generic type Class_1 (BTW: read about Java naming conventions) and then use addAll
yourList.addAll(theListFromDB);
try this
listInstance.addAll(anotherListInstavce) ;
First i would check if my source list, the one populated from DB has more than 1 element. If you are using JDBC, its a very common mistake to not move the result set objects further.
Secondly if you need such collection manipulation utilities i suggest take a look at commons-collections ListUtils class.
All the collections have a simple method to add data of one collection to other.
list2.addAll(list1);
You can simply use this method...

What causes this retainAll exception?

java.lang.UnsupportedOperationException: This operation is not supported on Query Results
at org.datanucleus.store.query.AbstractQueryResult.contains(AbstractQueryResult.java:250)
at java.util.AbstractCollection.retainAll(AbstractCollection.java:369)
at namespace.MyServlet.doGet(MyServlet.java:101)
I'm attempting to take one list I retrieved from a datastore query, and keep only the results which are also in a list I retrieved from a list of keys. Both my lists are populated as expected, but I can't seem to user retainAll on either one of them.
// List<Data> listOne = new ArrayList(query.execute(theQuery));
// DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
// List<Data> listTwo = new ArrayList(ds.get(keys).values());
// listOne.retainAll(listTwo);
EDIT
Ok, in an attempt to simplify, since this is apparently multiple problems in one, I have stopped using the low level API for datastore and instead of am just pulling one by one with a loop.
List<MyClass> test = (List<MyClass>) query.execute();
List<MyClass> test2 = new ArrayList<MyClass>();
for (String key : favorites) {
test2.add(pm.getObjectById(MyClass.class, key));
}
log.info(test.toString());
test.retainAll(test2);
The above works. It doesn't throw the exception. The below does throw the exception. The only difference is the log.info. I'm stumped.
List<MyClass> test = (List<MyClass>) query.execute();
List<MyClass> test2 = new ArrayList<MyClass>();
for (String key : favorites) {
test2.add(pm.getObjectById(MyClass.class, key));
}
test.retainAll(test2);
It will not let me do new ArrayList() on the query result since it returns an array of objects.
You however need to put them in a new ArrayList(). The returned List implementation apparently doesn't support retainAll(). That's what the exception is telling you.
A "plain" ArrayList supports it. If passing through the ArrayList constructor is not possible due to difference in generic type, then you'll need to manually loop over it and cast each item before adding.
List<Data> listTwo = new ArrayList<Data>();
for (Object object : ds.get(keys).values()) {
listTwo.add((Data) object);
}
listOne.retainAll(listTwo);
Update: as per your update, the entities are apparently lazily loaded/filled. Most ORM's (DataNucleus is one) may indeed do that. As I don't use DataNucleus, I can't go in detail how to fix that in a "nice" way. But you at least now know the root cause of the problem and it can be solved the same way as above. Fill the list test in a loop as well.
If the type of collection you use for your "list of keys" does not support retainAll that exception will be thrown. Which type are you using?
TIP: you don't need to iterate to fill listTwo.
just do:
listTwo.addAll(ds.get(keys).values())

Categories