Как получить объект из List по условию, при этом удалив его из списка?

134
05 марта 2021, 22:40

Есть класс Alpha, у него String name QWERTY
Есть Arraylist list Экземпляр туда добавлен, но вернуть его не могу.

Alpha ah1 = removeAndGet("QWERTY");
Alpha removeAndGet(String name) {
     Alpha temp = null;
     for(Alpha element: list) {
          if(element.getName().equals(name)) {
               temp = list.get(list.indexOf(element));
               list.remove(list.indexOf(element));
          }   
     }
     return temp;
}

Получаю:

Exception in thread "main" java.util.ConcurrentModificationException

Ни стрим , ничего не помогает. list.removeIf(o->o.equals(alpha)); это на удаление отдельно работает list.remove(list.indexOf(alpha)); и это тоже а по условию невозможно.

Answer 1

Через Stream

Изменять список внутри for-each нельзя. Можно отделить поиск от удаления через Stream API:

static Alpha removeAndGet(String name) {
    //получаем первый подходящий объект
    //или null, если таких нет
    Alpha temp = list.stream()
        .filter(a -> name.equals(a.getName()))
        .findFirst()
        .orElse(null);
    //удаляем *ВСЕ* объекты с таким именем
    list.removeIf(a -> name.equals(a.getName()));
    return temp;
}

Как @Andrew Bystrov пишет в комментах, здесь будет два прохода: первый — для поиска до найденного элемента, второй — для удаления по всему списку. С помощью Optional.isPresent можно попробовать избежать второго прохода если элемент не был найден.

Исполняемый пример (https://ideone.com/B1qski):

import java.util.*;
class Ideone {
    static List<Alpha> list;
    public static void main (String[] args) {
        String name = "qwerty";
        list = new ArrayList<>(Arrays.asList(new Alpha("foo"), new Alpha(name), 
                                             new Alpha("bar"), new Alpha("lol")));
        Alpha temp = removeAndGet(name);
        System.out.println(temp); //qwerty
        System.out.println(list); //[foo, bar, lol]
    }
    static Alpha removeAndGet(String name) {
        //получаем первый подходящий объект
        //или null, если таких нет
        Alpha temp = list.stream()
                         .filter(a -> name.equals(a.getName()))
                         .findFirst()
                         .orElse(null);
        //удаляем *ВСЕ* объекты с таким именем
        list.removeIf(a -> name.equals(a.getName()));
        return temp;
    }
    static class Alpha {
        String name;
        Alpha(String name) {
            this.name = name;
        }
        String getName() {
            return name;
        }
        @Override
        public String toString() {
            return name;
        }
    }
}

Через Iterator

Можно написать без Stream API, по-старому, через Iterator.remove:

Alpha removeAndGet(String name) {
    Alpha result = null;
    Iterator<Alpha> iterator = list.iterator();
    while(iterator.hasNext()) {
        Alpha a = iterator.next();
        if(name.equals(a.getName())) {
            //так будет присвоен последний найденный элемент
            //если важно выбрать первый, то нужно добавить проверку на null
            result = a; 
            iterator.remove();
        }
    }
    return result;
}

Пример: https://ideone.com/qnGQux

Answer 2

Надо использовать перебирание через i, foreach не предназначен для изменения списка:

Alpha removeAndGet(String name){
     Alpha temp = null;
     for(int i = 0; i < list.size();) {
         Alpha tmp = list.remove(i);
         if(tmp.getName().equals(name)) temp = tmp;
     }
     return temp;
 }
READ ALSO
Вычитание строк

Вычитание строк

Вычитанием строк назовем операцию при которой все буквы вычитаемого вычеркиваются из уменьшаемого, а если в уменьшаемом таких букв не было...

92
Java.Spring. BlockingQueue&lt;&gt;

Java.Spring. BlockingQueue<>

Я в спринге задаю бин

120
Spring WebSocket и SockJS c использованием JWT

Spring WebSocket и SockJS c использованием JWT

Есть приложение на Spring boot 2, в котором пользователи авторизуюца и получают access keyКлиентская часть крутится на nodejs

94
Ad failed to load

Ad failed to load

Не запускается баннер рекламы

73