0

I've been trying to remove an element in ArrayList using the remove() object but it is still not deleting anything. I already checked the list stored in my array and everything is displaying fine, but when I try to remove an element, It is not working. My goal was the user would input a name to remove and it would search through the list that is equal to that name and remove it. The List Array is set as global.

Here is the code:

public static void removeStudents() {
    String removeName;

    System.out.println("******REMOVE STUDENTS******");
    System.out.print("Enter name you wish to remove: ");
    removeName = hold.nextLine();

    hold.nextLine();

    for (int x = 0; x < fullName.size(); x++) {
        if (fullName.get(x).equalsIgnoreCase(removeName)) {
            fullName.remove(x);
        }
    }       
}
deHaar
  • 11,298
  • 10
  • 32
  • 38
  • 4
    You souldn't remove element from array which you actually iterate through – Kenik Dec 11 '19 at 14:52
  • You will run into `ConcurrentModificationException` soon, because you are modifying the content of the collection you are iterating over. You should use an iterator to remove List elements instead. – kidney Dec 11 '19 at 14:53
  • Does this answer your question? [How to avoid "ConcurrentModificationException" while removing elements from \`ArrayList\` while iterating it?](https://stackoverflow.com/questions/18448671/how-to-avoid-concurrentmodificationexception-while-removing-elements-from-arr) – JonK Dec 11 '19 at 14:54
  • If you store the values with lowercase in the ArrayList you would not need to search for the value before removing it. You could immediately perform `fullName.remove(x.toLowerCase());` – AndiCover Dec 11 '19 at 14:55
  • See this [https://stackoverflow.com/questions/1196586/calling-remove-in-foreach-loop-in-java](https://stackoverflow.com/questions/1196586/calling-remove-in-foreach-loop-in-java) – Chrisimir Dec 11 '19 at 14:58
  • 1
    "when I try to remove an element, It is not working" In what way is it not working? Please [edit] your question to describe specifically what happens. Do you get any errors or exceptions? What do the messages say? – Kenster Dec 11 '19 at 15:32
  • @kidney How that? `get()` does not throw that, code is not using an iterator! – user85421 Dec 11 '19 at 22:55
  • @Kenik why not? just need some care handling the index – user85421 Dec 11 '19 at 23:02
  • problem with that code is that it ignores the name following a deleted one (maybe never happens), that is, it is missing a `x--` after deleting; **and** must have the full name of the student to be deleted (assuming `fullName` is a list with full names) {sure, much easier to use `removeIf()` IMO} - question is not clear include sample data and maybe a [mcve] – user85421 Dec 11 '19 at 23:19
  • 1
    I wonder why there is a second `readLine()`? Is it possible that you are using a `Scanner` and the first `readLine()` is returning an empty string: https://stackoverflow.com/q/13102045/85421 – user85421 Dec 11 '19 at 23:28
  • @user85421 - I just checked today the variable removeName, and it does return an empty string. – Reynard Joseph Dec 12 '19 at 03:40
  • @user85421 - I finally figured it out, I basically changed all hold.nextLine() to hold.next(), and I also removed all hold.nextLine() that was in between lines. – Reynard Joseph Dec 12 '19 at 03:50
  • but still read [Max' answer below](https://stackoverflow.com/a/59288570/85421) - if the list have 2 (or more) identical entries the second will skipped and not removed - [deHaar's](https://stackoverflow.com/a/59288515/85421) is also an elegant solution – user85421 Dec 12 '19 at 07:48

3 Answers3

4

From Java 8 on, there is

Collection.removeIf(Predicate<? super E> filter)

You can easily remove elements matching specified criteria from a List, but you shouldn't do it while iterating that list because its indexes would change and that possibly leads to a ConcurrentModificationException as already mentioned in one of the comments below your question.

Do it like this:

public static void main(String[] args) {
    // provide sample data
    List<String> students = new ArrayList<>();
    students.add("Student 01");
    students.add("Student 02");
    students.add("Student 03");
    students.add("Student 04");
    students.add("Student 05");
    students.add("Student 06");
    // print the list once before any operation
    System.out.println("Before:\t" + String.join(", ", students));
    // remove elements matching certain criteria, here equality to "Student 03"
    students.removeIf(student -> student.equalsIgnoreCase("Student 03"));
    // print the list after removal of "Student 03"
    System.out.println("After:\t" + String.join(", ", students));
}

The output is

Before: Student 01, Student 02, Student 03, Student 04, Student 05, Student 06
After:  Student 01, Student 02, Student 04, Student 05, Student 06

Please note that this example just uses a List<String>, if you have a List<Student>, you would specify the criterium for removal like

students.removeIf(student -> student.getName().equalsIgnoreCase(removeName));
deHaar
  • 11,298
  • 10
  • 32
  • 38
  • 1
    sorry, but code posted in question is **not** affected by `ConcurrentModificationException`; neither `size()`, `get()` nor `remove()` will throw that exception. - this would be an issue if using the enhanced `for` loop (`for-each`) – user85421 Dec 11 '19 at 23:24
  • Yes, my code just uses List. But where did you get the student variable? because its giving me errors on that part. – Reynard Joseph Dec 12 '19 at 03:20
  • @ReynardJoseph that variable is part of a lambda expression which are available since Java 8. What kind of error does it give you? – deHaar Dec 12 '19 at 06:13
  • @user85421 Thanks for the hint, I have rephrased the part about the `ConcurrentModificationException` which doesn't get thrown by OP's code, but may be thrown in a similar context. – deHaar Dec 12 '19 at 07:46
1

Lets say you have ArrayList of Strings with student names and its size is 5. Whenever you find the String to remove, in next iteration of for loop, you will skip one ArrayList element. You can overcome this by decrementing your for loop iterator, which is a working solution, but not the best. If your loop is on third element (fullName.get(2)) and it matches your deletion criteria, you will delete it and now have an ArrayList of 4 elements, not 5, where in next iteration (fileName.get(3)) you will actually skip one ArrayList element that had shifted to deleted elements position (whole ArrayList had shifted obviously).

public static void removeStudents(){
    String removeName;

    System.out.println("******REMOVE STUDENTS******");
    System.out.print("Enter name you wish to remove: ");
    removeName = hold.nextLine();

    hold.nextLine();

    for(int x=0 ; x<fullName.size() ; x++){
        if(fullName.get(x).equalsIgnoreCase(removeName)){
            fullName.remove(x);
            x--;
        }
    }       
}

This should work but as someone commented above, using an Iterator would be a better solution.

0
public static void removeStudents(){
    String removeName;

    System.out.println("******REMOVE STUDENTS******");
    System.out.print("Enter name you wish to remove: ");
    removeName = hold.nextLine();

    hold.nextLine();

    // collecting the objects that we want to delete
    List<String> foundList = new ArrayList<String>();

    for(int x = 0; x < fullName.size();x++){
        if(fullName.get(x).equalsIgnoreCase(removeName)){
            foundList.add(fullName.get(x));
        }
    }

    // delete objects
    fullName.removeAll(foundList);
}
koding
  • 135
  • 1
  • 8