getting ConcurrentModificationException error while using iterator and remove - java

I am getting a java.util.ConcurrentModificationException from following code and I can find the reason. I could successfully read data form a csv file and make an arraylist called course list of it. then I need to sort my in to an array list that each of its cell contains an arraylist of identical courses (courses that have similar name).
But when I run it generates ConcurrentModificationException and I do not understand why...
public class CourseLister {
private static final String DATA = "data\\data.csv";
File file;
ArrayList<Course> courseList ;
public CourseLister(String filepath) {
file = new File(filepath);
courseList = new ArrayList<>();
}
public void readFromCsv(){
// in this method a Csv file is written line by line , create a new object of course with some attribute such as name , number, instructor,... and is added to courseList //}
}
public Iterator<Course> getCourseIterator(){
return courseList.iterator();
}
public ArrayList<Course> getCourseList(){
return courseList;
}
public static void main(String [ ] args){
CourseLister courseLister = new CourseLister(DATA);
courseLister.readFromCsv();
CourseFileSorter coursefilesoreter = new CourseFileSorter(courseLister.getCourseIterator());
ArrayList<Course> curseList = courseLister.getCourseList();
for (Course course : curseList) {
System.out.println(course.getSemester());
}
System.out.println(curseList.size());
coursefilesoreter.displayCategorizedList();
}
}
here is my CourefileSorterclass:
public class CourseFileSorter {
Iterator<Course> courseItr ;
public CourseFileSorter(Iterator<Course> courseItr) {
this.courseItr = courseItr;
}
public ArrayList<ArrayList<Course>> getSourtedLists(){
Iterator<Course> dissimilarCourseItr = null;
ArrayList<Course> identicalCourseList = new ArrayList<Course>();
ArrayList<Course> dissimilarCourseList = new ArrayList<Course>();
ArrayList<ArrayList<Course>> categorizedCourseList = new ArrayList<ArrayList<Course>>();
Course firstCourse = null;
Course currentCourse ;
if(courseItr.hasNext()){
while(courseItr.hasNext()){
firstCourse = courseItr.next();
identicalCourseList.add(firstCourse);
while(courseItr.hasNext()){
currentCourse = courseItr.next();
if(currentCourse.getCourseName().equals(firstCourse.getCourseName())){
identicalCourseList.add(currentCourse);
courseItr.remove();
}
else{
dissimilarCourseList.add(currentCourse);
}
}
dissimilarCourseItr = dissimilarCourseList.iterator();
courseItr = dissimilarCourseItr;
categorizedCourseList.add(identicalCourseList);
}
return categorizedCourseList;
}
else{
return null;
}
}
}

It would be much easier to sort them into a different data structure. I see that course has a getCourseName() method, which I assume would return a String object. Try using a Map<String, List<Course>> instead.
The sorting method would look like this:
public Map<String, List<Course>> getSourtedLists(){
Map<String, List<Course>> result = new HashMap<String, List<Course>>();
while(courseItr.hasNext()) {
course next = courseItr.next();
if (!result.containsKey(next.getCourseName())) {
result.put(next.getCourseName(), new ArrayList<Course>());
}
result.get(next.getCourseName()).add(next);
}
Also, you REALLY don't want to call courseItr.remove(); This removes the course object from the underlying Collection, meaning that the way you were planning to do it would empty out the courseList from your CourseLister object.

1 . You get ConcurrentModificationException because:
dissimilarCourseList.add(currentCourse);
courseItr = dissimilarCourseItr;
2 . It's not a good idea to use iterators when you have arraylists.

Related

Passing List of class objects to config file

I have got class:
class Region{
String name;
List<String> BlockPlayers = new ArrayList<>();
}
Then I made a List of objects in my program like this
List<Region> playersRegions = new ArrayList<>();
Now I need to make a function that will pass objects from playersRegions list to config file. Then I need to make function that will load everything from config file and pass to playersRegions list
I have made something like this
private void save_regions_inConfig()
{
getConfig().set("locs", playersRegions);
saveConfig();
}
But I have no idea how to load it from file to playersRegions. I just want to keep everything after I close the program and open it once more.
You should define a way to format the region.
Let assume method are on your JavaPlugin class and everything else is well made (plugin.yml valid etc)
To write them, use something like this:
public void saveRegion(List<Region> regions) {
FileConfiguration config = getConfig();
int i = 0;
for(Region r : regions) {
config.set("regions." + i + ".name", r.name);
config.set("regions." + i + ".blockplayers", r.BlockPlayers);
i++;
}
saveConfig();
}
The config file will be like this:
regions:
0:
name: "Region 1"
blockplayers:
- "Something"
Now, to read it, you should do something like that:
public List<Region> getRegion() {
ConfigurationSection config = getConfig().getConfigurationSection("regions");
if(config == null) // no region set yet
return new ArrayList<>();
List<Region> list = new ArrayList<>();
for(String keys : config.getKeys(false)) {
ConfigurationSection regionConfig = config.getConfigurationSection(keys);
list.add(new Region(regionConfig.getString("name"), region.getStringList("blockplayers")));
}
return list;
}
Note: you should define a constructor in your Region object like that:
public class Region{
String name;
List<String> blockPlayers = new ArrayList<>();
public Region(String name, List<String> blockPlayers) {
this.name = name;
this.blockPlayers = blockPlayers;
}
}
Finally, some of your name (method or variable) doesn't meet the Java convention. Specially about method, but that's a detail.
This should work
public List load_playerRegions_fromConfig(List<Region> playersRegions) {
return getConfig().getList("locs", playersRegions);
}

Hierarchical Data to arrayList using recursion. (Java)

I have hierarchical data in MySQL of employees and their subordinates as shown here There is a joining column 'managerID' which references to the employee ID in the same column.
My objective is to recursively go through this data and add it all to an arrayList which would end up looking like this:
[Tom [Hanna [George [Chris], Rachel]]]
But there is a logic problem in my java function:
public void getList(String employeeName, ArrayList<Object> arrayList) {
// Initialise the arrayList the first time
if (arrayList == null) {
arrayList = new ArrayList<>();
}
// Using the string provided, I have found the employee
Employee employee = employeeRepository.findByName(employeeName);
// adding employee to the list
arrayList.add(employee);
// Getting list of employee's subordinates
List<Employee> subordinates = employee.getSubordinates();
// Checking if employee has subordinates
if (subordinates != null) {
// Iterate through each of their subordinates and call recursive function
for (int i = 0; i < subordinates.size(); i++) {
ArrayList<Object> subOrdinateDetails = new ArrayList<>();
// If the subordinate has subordinates, use recursion
if (subordinates.get(i).getSubordinates() != null) {
getList(subordinates.get(i).getName(), subordinatesDetails);
}
// Adding this list to the original arrayList
arrayList.add(subOrdinateDetails);
}
System.out.println(arrayList.toString());
}
}
The toString method at the end of the method does not print what I wanted above, instead it prints:
[Chris]
[George, [Chris]]
[Rachel]
[Hanna, [George, [Chris]], [Rachel]]
[Tom, [Hanna, [George, [Chris]], [Rachel]]]
While trying to debug it, I tried to get the first index of the arrayList, to understand what it was here is what it printed:
Chris
George
Rachel
Hanna
Tom
As you can tell, I am new to java, and I have failed debugging my code. If you could point out my mistake, I will be very grateful.
You can simply do it like this.
public class Employee {
private final String name;
private final List<Employee> subordinates;
public Employee(String name, List<Employee> subordinates) {
super();
this.name = name;
this.subordinates = subordinates;
}
public String getName() {
return name;
}
public List<Employee> getSubordinates() {
return subordinates;
}
public void print() {
System.out.println(this.name);
this.subordinates.forEach(emp -> {
emp.print();
});
}
}
public class EmployeeTest {
public static void main(String[] args) {
Employee chris = new Employee("chris", new ArrayList<>());
Employee george = new Employee("george", Arrays.asList(chris));
Employee rachell = new Employee("rachell", new ArrayList<>());
Employee hannah = new Employee("hannan", Arrays.asList(george, rachell));
Employee tom= new Employee("tom",Arrays.asList(hannah));
tom.print();
}
}
The trick in the recursion is each time it prints out the current employee, before printing any of it's subordinates as you can see in the method. I'll leave it to you to come up with the brackets if needed.

transform Collection<myClass> to Collection<String>

I trying to implement functionally similar to CollectionUtils transform (Apache Commons Collections)
class CollectionUtils {
public static void transformerModifier(Collection<MyClass> myCollection) {
// How should I implement this method in order that
// output from the line 1 and line 2 will be the same ?
}
public static List<String> transform(Collection<MyClass> myCollection) {
List<String> strCollection = new LinkedList<>();
for (MyClass item : myCollection) {
strCollection.add(item.getName());
}
return strCollection;
}
}
class myClass {
private String name;
private int value;
myClass( String name, int value) {
this.name = name ;
this.value = value;
}
public String toString(){
return new String(name+ ":" + value ) ;
}
}
class MyClassCollection{
private List<myClass> list ;
myClassCollection(List<myClass> list){
this.list = list;
}
List<myClass> collection(){
return list.clone();
}
}
public class TestClass{
public static void main (String[] args) {
List<MyClass> list = new ArrayList<>();
list.add(new myClass("John", 12);
list.add(new myClass("Mike", 16);
list.add(new myClass("Eric", 13);
list.add(new myClass("Mark", 142);
list.add(new myClass("Alex", 112);
MyClassCollection myOjb = new MyClassCollection(list );
CollectionUtils.transformerModifier(myObj.collection() );
List<MyClass> myList = CollectionUtils.transform(myObj.collection());
System.out.println(Arrays.toString(myObj.collection().toArray)); // line 1
System.out.println(Arrays.toString(myList.toArray)); // line 2
}
}
output: [John,Mike,Eric,Mark,Alex] // output after line 1
output: [John,Mike,Eric,Mark,Alex] // should be output after line 2
My question is it possible to implement method transformerModifier in the way that it will change collection of the object myObj so that myObj.collection() return not the List<myClass> but the List of List<String> ( where string is the data from private String name data member of myClass ) ?
My guess is that the solution should be through anonymous class. However, I didn't understand yet how should I implement it.
If you are using Java 8, you could make use of streams and map() to do something like this:
List<MyClass> myClassList = new ArrayList<>();
//add your items to myClassList here
List<String> names = myClassList.stream().map(MyClass::getName).collect(Collectors.toList());
//names will now consist of a List of all the names associated with
//each of the MyClass objects within myClassList in the same order
This solution makes use of Method Reference as well MyClass::getName. This calls the getName method on each object in the stream mapping it to its respective spot in the transformed stream using .map().
Next it uses .collect() to bring it back from a stream to a list using Collectors.toList().
If you are working with a lot of objects within myClassList, this process can be sped up using .parallelStream() instead of .stream(), but if you are not working with a large amount of data, you may see a reduction in performance with .parallelStream(). It all depends on how many objects you expect to be present within the List.
public interface Converter<I, O> {
void tranformer(List list);
O retriever(I obj);
}
_
public static <I, O> void transform(Converter<I, O> converter, List inputList) {
Iterator<I> it = inputList.iterator();
List list = new LinkedList<>();
while (it.hasNext()) {
list.add(converter.retriever(it.next()));
}
converter.tranformer(list);
}
_
public static void main(String[] args) {
List<MyClass> list = new ArrayList<>();
list.add(new myClass("John", 12);
list.add(new myClass("Mike", 16);
list.add(new myClass("Eric", 13);
list.add(new myClass("Mark", 142);
list.add(new myClass("Alex", 112);
MyClassCollection myclasscollection = new MyClassCollection(list);
final List collectionList = myclasscollection.collection();
CollectionUtils.transform(new Converter<myClass, String>() {
#Override
public void tranformer(List list) {
employeeList.clear();
employeeList.addAll(list);
}
#Override
public String retriever(myClass obj) {
return obj.name; // make the data member public or add getter
}
}, collectionList);
collectionList.get(0).toString.toLowerCase();
}
This isn't fully what you need but I bet this isn't bad alternative. Please, notice that could output collection collectionList will be collection of objects ( not String ), however, you can access to methods of the String data type just to right like this collectionList.get(0).toString.toLowerCase(); Hope this help.

How to create a list of objects and access to their attributes

I created an object N, which has some attributes, like this:
public class LogEvidence {
private String comment;
private String url;
private String time;
public LogEvidence(String comentario, String url, String tiempo) {
super();
this.comment = comentario;
this.url = url;
this.time = tiempo;
}
public String getComentario() {
return comment;
}
public void setComentario(String comentario) {
this.comment = comentario;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getTiempo() {
return time;
}
public void setTiempo(String tiempo) {
this.time = tiempo;
}
#Override
public String toString() {
return "LogEvidence [comentario=" + comment + ", url=" + url + ", tiempo=" + time + "]";
}
}
Now I want to do something like this:
ArrayList<LogEvidence>log = new ArrayList<LogEvidence>();
I want go through the list and add all the attributes to my object, I mean something like this:
log.setComment("comment one");
log.setUrl("http://google.com");
log.setTime("04:20");
Maybe this is not possible and I have to do something like the following?
List list= new List();
LogEvidence object1= new LogEvidence ();
object1.setComment("comment");
object1.setUrl("http://url.com");
object1.setTime(20);
lista.add(object1);
This is how you can do it:
Create an object of LogEvidence.
LogEvidence logEvidence = new LogEvidence();
logEvidence.setComentario("comment one");
logEvidence.setUrl("http://google.com");
logEvidence.setTiempo("04:20");
and add it into the array list.
log.add(logEvidence);
So, you can then create more objects and keep putting in the list. Since your list is named as log, so that is why you will add in log
Explaining it a little more, it should be something like this:
List<LogEvidence> logEvidenceList = new ArrayList<>();
LogEvidence logEvidence1 = new LogEvidence();
logEvidence1.setComentario("comment one");
logEvidence1.setUrl("http://google.com");
logEvidence1.setTiempo("04:20");
logEvidenceList.add(logEvidence1);
LogEvidence logEvidence2 = new LogEvidence();
logEvidence2.setComentario("comment one");
logEvidence2.setUrl("http://google.com");
logEvidence2.setTiempo("04:20");
logEvidenceList.add(logEvidence2);
....
....
....
Or through constructor call, this will become more concise and readable.
List<LogEvidence> logEvidenceList = new ArrayList<>();
LogEvidence logEvidence1 = new LogEvidence("comment one","http://google.com","04:20");
logEvidenceList.add(logEvidence1);
LogEvidence logEvidence2 = new LogEvidence("comment one","http://google.com","04:20");
logEvidenceList.add(logEvidence2);
....
....
....
Now, when you want to retrieve objects from the list, you can traverse the list and get one by one like;
for (LogEvidence evidence : logEvidenceList) {
System.out.println(evidence);
}
For more information about ArrayList
As Kon commented, you are trying to act upon an object that will be within the list, rather than the list itself.
There are a few ways to do this, but since you have a parameterized construtor, the easiest would be this:
ArrayList<LogEvidence> log = new ArrayList<LogEvidence>();
log.add(new LogEvidence("comment one", "http://url.com", "04:20");
What's being done:
We create the list with new ArrayList<LogEvidence>() and assign it to a variable called log.
Then, we create a new LogEvidence object, already assigning it's data through it's constructor's parameters, with new LogEvidence("comment one","http://url.com","04:20").
Since it will be stored in the list, we can use it anonymously. We add it to the list directly, using the list's .add(E e) method, rather than assigning it to a variable.
You don't need to define or assign unnecessary variables, in this case.
And if you need to access any specific LogEvidence from the list, you can use the .get(int index) method. In this case, log.get(0), to return the first element, would return the object you just inserted in the example code above.
You can also use a FOR-EACH LOOP to act upon all objects in the list, in iterating manner. Here is an example that prints the list:
for (LogEvidence evidence : log) {
System.out.println(evidence);
}

Copying contents of file into array of linked list and sort it

I have a comma separated file that contains
Employee name,company,years.
An employee may be affiliated to multiple companies.
For eg,
John,Google,2
John,Microsoft,1
James,Tesla,1
James,Apple,5
I have retrieved the information using the java scanner
scanner.useDelimiter(",|\\n");
while (scanner.hasNext()) {
String line = scanner.next()
I am new to Java and I am trying to insert the above in a sorted order (using experience as sorting criteria) using an array of linked lists or array of array. So
employee -> Company1 -> Company2.... (ordered by employee experience)
So in the above example, it would be:
John->Microsoft->google
James->Tesla->Apple
Can someone point me to the right direction?
NOTE: If the experience is same, it doesnt matter which company comes first.
Use this class for Person
public class Person {
#Getter #Setter
private String name;
#Getter #Setter
private TreeMap<String, String> companyExperience;
public Person(){
companyExperience = new TreeMap<String, String>();
}
}
Using the experience as key in a TreeMap will automatically sort the companies for a Person in ascending order.
Your main class shoud look like this
public class App
{
public static void main( String[] args )
{
HashMap<String, Person> persons = new HashMap<String, Person>();
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("C:\\Users\\Public Administrator\\test.txt"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String line = null;
try {
while ((line = br.readLine()) != null) {
String[] fields = line.split(",");
String personName = fields[0];
Person existingPerson = persons.get(personName);
if (existingPerson==null){
Person newPerson = new Person();
newPerson.setName(personName);
newPerson.getCompanyExperience().put(Integer.parseInt(fields[2])+fields[1], fields[1]);
persons.put(personName, newPerson);
} else{
existingPerson.getCompanyExperience().put(Integer.parseInt(fields[2])+fields[1], fields[1]);
}
}
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//output
Iterator<Map.Entry<String, Person>> entries = persons.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, Person> entry = entries.next();
Person _person = entry.getValue();
System.out.print(_person.getName());
Iterator<Map.Entry<String, String>> companyExperiences = _person.getCompanyExperience().entrySet().iterator();
while (companyExperiences.hasNext()) {
Map.Entry<String, String> companyExperience = companyExperiences.next();
System.out.print(" > "+companyExperience.getValue());
}
System.out.println();
}
}
}
I've tested it and looks pretty, pretty good to me.
By the way, the #Getter and #Setter annotations are from the Lombok project. You can either use it or create your own getters/setters.
read your file with readLine() and use split to get each field of your data, e.g.:
BufferedReader br = new BufferedReader(new FileReader("FileName"));
String line = null;
ArrayList<Person> list = new ArrayList<Person>();
while ((line = br.readLine()) != null) {
String[] fields = line.split(",");
list.add(new Person(fields[0], fields[1], Integer.parseInt(fields[2])));
}
You can then save your data in ArrayList that takes a custom class e.g. Person that stores the person's information and implements Comparable where you do the sorting logic.
If you need to group your data by the person name, you might consider having a Hashtable where the key is the person name and the value is ArrayList of experience.
You can define a class for your data, e.g.
class Person implements Comparable<Person> {
private String name;
private String company;
private int experience;
public Person(String name, String company, int experience) {
this.name = name;
this.company = company;
this.experience = experience;
}
public int getExperience() {
return experience;
}
#Override
public int compareTo(Person person) {
return new Integer(experience).compareTo(person.getExperience());
}
}
The to sort your list just call Collections.sort(list);; however this list will contain all the data so modify the code to group the data by the employee name and have a list per each employee
For your purposes, it sounds like you really want an object to represent a Person, who has some amount of Experience. Since your input source has the data denormalized, easiest way to do that is to populate a Map<String,Person> as you parse your file:
scanner.useDelimiter(",|\\n");
while (scanner.hasNext()) {
String line = scanner.next();
String[] fields = line.split(",");
String name = fields[0];
Person person = map.get(name);
if (person == null) {
person = new Person(name);
map.put(name, person);
}
person.addJob(fields[1], Integer.parseInt(fields[2]));
}
List<Person> people = new ArrayList<Person>(map.values());
After this process, you'll end up with a List of People, in no particular order. For each Person, since you want to keep their job's in order sorted by experience, you'd need to implement Person.addJob in such a way as to keep it ordered. A SortedSet is a really nice way to do this, but you can't insert duplicates, and since you want to sort by experience, and a person could've been at two jobs the same amount of time you need to use an alternate approach. There's several ways to do this, but without making assumptions about your data I'd suggest keeping a sorted List of Job objects:
class Person {
private final List<Job> jobs = new LinkedList<Job>();
// Constructor, etc...
public void addJob(String companyName, int yearsOfExperience) {
Job newJob = new Job(companyName, yearsOfExperience);
int insertionIndex = Collections.binarySearch(jobs, newJob);
if (insertionIndex < 0) {
insertionIndex = (-(insertionIndex) - 1);
}
jobs.add(insertionIndex, newJob);
}
}
and finally, a Job should implement Comparable<Job>, so that you can look it up:
class Job implements Comparable<Job> {
private final String companyName;
private final int yearsOfExperience;
// Constructor, etc...
public int compareTo(Job otherJob) {
return Integer.compare(yearsOfExperience,otherJob.yearsOfExperience);
}
}
That bit of trickery in Person.addJob will keep the List always sorted by the 'natural order' of Job. (see Collections.binarySearch).

Categories