When you remove an item from the list, the indices change, which is not only causing the IndexOutOfBounds, but could mean you're removing the wrong values
Now, there are going to be a multitude of ways you might achieve this, for example...
List<String> name = new ArrayList<>(Arrays.asList(new String[]{"a", "b", "a"}));
List<String> discard = new ArrayList<>(25);
for (int outter = 0; outter < name.size(); outter++) {
String match = name.get(outter);
discard.clear();
for (int inner = outter + 1; inner < name.size(); inner++) {
String to = name.get(inner);
if (match.equals(to)) {
discard.add(to);
}
}
if (discard.size() > 0) {
discard.add(match);
name.removeAll(discard);
}
}
System.out.println(name);
This prints...
[b]
This simply collects any matching elements within the inner loop and places them into another List, which is then passed to the removeAll method of the original List after the inner loop has completed
The inner loop starts at the current/outer index (plus 1), as we've already processed all the values before it, so we shouldn't need to continue looping over those items
In theory, you could simply keep adding elements to the discard List and do a single removeAll at the end instead
Updated...
So, I was wondering if there might be another way to approach the problem using Java 8 and it's Stream support...
List<String> name = new ArrayList<>(Arrays.asList(new String[]{"a", "b", "a"}));
Set<String> allItems = new HashSet<>();
List<String> duplicates = name.stream()
.filter(n -> !allItems.add(n)) //Set.add() returns false if the item was already in the set.
.collect(Collectors.toList());
name.removeAll(duplicates);
So, basically, what this does is it collects all the duplicates in the name List and places them into the duplicates List (using the allItems as a temporary holding point).
Then you can simply use it to call removeAll to remove all the duplicate items.
Now, this relies on the hashcode and equals implementations of the objects to work