-2

I have been trying to remove null entries from an ArrayList without success.

First, I store all words from a file into an ArrayList using specific delimiters (punctuation and whitespace).

Then I attempt to remove null entries from the ArrayList.

When I print the whole list, the null entries are still there.

How can I solve this?

            ArrayList<String> words = new ArrayList<String>();
            while (scanner.hasNext()) {
                words.add(scanner.next());
            }

            for (int i = 0; i < words.size(); i++) {
                if (words.get(i) == null)
                {
                    words.remove(i);
                }
            }

Example of current output:

[10, years, , , 3, Lec, , , 3, Lab, , , , Coordinating, Board, Academic, Approval, Number, 1102015707, ]

Example of desired output:

[10, years, 3, Lec, 3, Lab, Coordinating, Board, Academic, Approval, Number, 1102015707]
mtzsouza
  • 19
  • 5
  • 1
    Those aren't `null` elements (if they were `null` you would be seeing the word "null" in the output). Likely they're empty `String`s. Doing something like `words.removeIf(String::isEmpty)` might work for you. – Slaw Feb 07 '23 at 07:28
  • 2
    One problem is that after you've removed (say) element 3, you're still incrementing `i` (to 4) but the *previous* element 4 is now element 3, and you're not checking it. The typical ways of fixing that are either to decrement `i` after calling `words.remove(i)`, or go from the *end* of the list towards the start (so `for (int i = words.size() - 1; i >= 0; i--)`). – Jon Skeet Feb 07 '23 at 07:29

2 Answers2

1

Try looping backwards:

        for (int i = words.size(); --i >= 0; ) {
            if (words.get(i) == null)
            {
                words.remove(i);
            }
        }
Maurice Perry
  • 9,261
  • 2
  • 12
  • 24
1

You have two problems:

  1. Your list doesn't contain any null elements. If there were null elements in the list, then you'd be seeing output like this:

    [10, years, null, null, 3, Lec, null, null, 3, Lab, null, null, null, Coordinating, Board, Academic, Approval, Number, 1102015707, null]    
    

    What you're most likely seeing is empty strings (""), or possibly blank strings (i.e., strings that contain only whitespace).

  2. You're incrementing i even when you remove an element. The problem with this is explained in John Skeet's comment under your question:

    One problem is that after you've removed (say) element 3, you're still incrementing i (to 4) but the previous element 4 is now element 3, and you're not checking it. The typical ways of fixing that are either to decrement i after calling words.remove(i), or go from the end of the list towards the start (so for (int i = words.size() - 1; i >= 0; i--)).

There are a few approaches you could use to fix the problem. All the code below tests if a string is blank via String#isBlank() (instead of testing for nulls).

Loop Backwards

for (int i = words.size() - 1; i >= 0; i--) {
    if (words.get(i).isBlank()) {
        words.remove(i);
    }
}

Use an Iterator

// for-loop version
for (Iterator<String> itr = words.iterator(); itr.hasNext(); ) {
    if (itr.next().isBlank()) {
        itr.remove();
    }
}

// while-loop version
Iterator<String> itr = words.iterator();
while (itr.hasNext()) {
    if (itr.next().isBlank()) {
        itr.remove();
    }
}

Use removeIf, passing a Predicate

// anonymous class version
words.removeIf(new Predicate<>() {
    @Override public boolean test(String word) {
        return word.isBlank();
    }
});

// lambda "block" version
words.removeIf(word -> {
    return word.isBlank();
});

// single-expression lambda version
words.removeIf(word -> word.isBlank());

// method reference version
words.removeIf(String::isBlank);
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Slaw
  • 37,820
  • 8
  • 53
  • 80