Помощник для удаления нулевых ссылок в списке Java?

Учитывая следующий список:

List<String> list = new ArrayList<String>();

list.add("s1");
list.add("s2");
list.add(null);
list.add("s3");
list.add(null);
list.add("s4");

Мне нужен вспомогательный класс, который удаляет нулевые ссылки. Что-то вроде:

SomeHelper.removeNullReference(список);

так что список содержит только "s1", "s2", "s4", "s4" (непустые ссылки).

Что следует использовать для выполнения этого требования?

Ответ 1

list.removeAll(Collections.singleton(null));

Ответ 2

Java 8 добавила Collection.removeIf(Predicate), которая удаляет все элементы, соответствующие предикату, поэтому вы можете удалить все вхождения null из списка ( или любой коллекции) с помощью

list.removeIf(Objects::isNull);

используя java.util.Objects.isNull как Predicate.

Вы также можете использовать .removeIf(x -> x == null), если хотите; разница очень незначительная.

Ответ 3

Если вы можете управлять созданием List, тогда вы можете предотвратить добавление нулей путем записи пользовательской реализации List, например:

public class NoNullsList<E> extends ArrayList<E> {

  public void add(int index, E element) {
    if (element != null) {
      super.add(index, element);
    }
  }

  public boolean add(E e) {
    return e == null ? false : super.add(e);
  }
}

AFAIK, вам не нужно переопределять addAll, потому что его реализация ArrayList вызывает add.

List<String> list = new NoNullsList<String>();

list.add("s1");
list.add("s2");
list.add(null);
list.add("s3");
list.add(null);
list.add("s4");

Ответ 4

Недостатком подхода Don является то, что он простирается от ArrayList. На данный момент это может быть достаточно хорошим, но что происходит, когда вы хотите использовать другую реализацию List? Вы можете сделать NoNullsLinkedList и NoNullsCopyOnWriteArrayList, и т.д., Но затем вы соберете кучу небольших классов, которые отличаются только их предложением extends. Возможно, было бы лучше создать оболочку List, которая не принимает значения null. Например:

public class NonNullList<E> extends AbstractList<E> {
  private final List<E> delegate;

  public NonNullList(List<E> delegate) {
    this.delegate = delegate;
  }

  @Override
  public E get(int index) {
    return delegate.get( index );
  }

  @Override
  public int size() {
    return delegate.size();
  }

  @Override
  public E set(int index, E element) {
    return delegate.set( index, element );
  }

  @Override
  public void add(int index, E element) {
    if( element != null ) {
      delegate.add( index, element );
    }
  }

  @Override
  public E remove(int index) {
    return delegate.remove( index );
  }
}

Это больше кода, но теперь у вас есть гибкость при выборе реализации List при создании объекта.

Возможная проблема заключается в том, что вы можете поместить null в базовый объект List. Дон подход не имеет того же ограничения.

Ответ 5

Мне очень нравится новое сжатое решение Java 8, я считаю, что вы должны использовать это, когда это возможно.

list.removeIf(Objects::isNull);

С другой стороны, если вы ищете простую реализацию, чтобы узнать, как это можно сделать, например, вспомогательный класс, который возвращает новый ненулевой список, вы можете взглянуть на следующий код. Также можно принять общие типы, для простоты я использовал один и тот же тип коллекции (как в вопросе) в классе-помощнике.

package removenullrefdemo;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

class ListHelper {
    public static List<String> removeNullReference(List<String> list) {
        List<String> newList = new ArrayList<>();

        list.forEach(item -> {
            if (item != null)
                newList.add(item);
        });

        return newList;
    }
}

public class Main {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();

        list.add("s1");
        list.add("s2");
        list.add(null);
        list.add("s3");
        list.add(null);
        list.add("s4");

        println("Items:");
        list.forEach(item -> println(item));

        // Remove null refs
        println("Items (after nulls removed):");
        boolean useJava8removeIf = false;
        if (useJava8removeIf) {
            println("Using Java8 removeIf method with predicate.");
            list.removeIf(Objects::isNull);
        }
        else {
            println("Using our own helper.");
            list = ListHelper.removeNullReference(list);
        }

        list.forEach(item -> println(item));

    }

    static void println(String msg) {
        System.out.println(msg);
    }
}

Ответ 6

removeAll не работает для меня. Вместо этого я создаю новый список:

new ArrayList<E>(list);

Просто как это.