2009-08-06 10 views
35

Zważywszy na poniższej liście:Pomocnik do usuwania pustych odniesień na liście 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"); 

muszę klasy pomocnika, który usuwa odniesienia null. Coś jak:

SomeHelper.removeNullReference (lista);

taka, że ​​lista zawiera tylko "S1", "S2", "S4", "S4" (referencje non-null).

Co powinienem użyć, aby spełnić ten wymóg?

Odpowiedz

103
list.removeAll(Collections.singleton(null)); 
+0

Fajnie, nie wiedziałem o singletonList(). To jest bardziej eleganckie niż mój trójliner. –

+4

Klasy Kolekcje i Tablica są prawdziwymi skarbami - i singletonList(), a także emptyList() są głównymi powodami, dla których użycie parametru ArraList lub Vector jako metody parametru wszędzie powinno być karane co najmniej 20 batami. –

+3

Mogłoby to być również 'list.removeAll (Arrays.asList (null))', ale 'singletonList' jest nieco szybszy. –

3

Jeśli można kontrolować konkretyzacji w List następnie można zapobiec null dodawanych pisząc realizację niestandardowych List takich jak:

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, nie trzeba zastąpić addAll ponieważ jego implementacja ArrayList wywołuje 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"); 
+1

Przyjemne podejście! (+1) –

+1

Te metody "add" naruszają umowę "List.add" (lub faktycznie Collection.add). Jeśli chcesz zabezpieczyć elementy puste, wyślij wyjątek (np. IllegalArgumentException) zamiast zwracać "false". –

+1

@ PaŭloEbermann Kiedy tworzysz klasę dla wyraźnego celu ignorowania wartości null (nie blokując wartości zerowych, jak widać z PO), nie ma sensu wyrzucać wyjątku w (oczekiwanym) przypadku dodania wartości zerowej . – Thor84no

3

Wadą podejścia Dona jest to, że rozciąga się on od ArrayList. To może być na razie wystarczająco dobre, ale co się stanie, gdy będziesz chciał użyć innej implementacji List? Możesz zrobić NoNullsLinkedList i NoNullsCopyOnWriteArrayList itd., Ale kończysz z grupą małych klas, które różnią się tylko klauzulą ​​extends. Lepszym rozwiązaniem może być utworzenie opakowania typu List, które nie akceptuje wartości pustych. Na przykład:

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); 
    } 
} 

To więcej kodu, ale teraz masz możliwość wyboru implementację List podczas tworzenia obiektu.

Możliwym problemem jest możliwość wstawienia null s do bazowego obiektu List. Podejście Dona nie ma tego samego ograniczenia.

+3

Oprócz odpowiedzi Dona twoja klasa narusza kontrakt z 'List.add' (lub właściwie' Collection.add'). Gdy metoda add zwraca (true lub false), element powinien być gwarantowany jako element równy elementowi dostarczonemu, którego implementacja nie zawiera. Zamiast tego wyrzuć wyjątek lub przynajmniej udokumentuj, że naruszasz umowę. –

-2

removeAll nie działa dla mnie. Zamiast tego tworzę nową listę:

new ArrayList<E>(list); 

To proste.

+2

To nadal ma jednak puste elementy, więc będziesz musiał je później usunąć. –

0

Bardzo podoba mi się nowe, zwięzłe rozwiązanie Java 8, uważam, że powinieneś go używać, gdy tylko jest to możliwe.

list.removeIf(Objects::isNull); 

Z drugiej strony, jeśli szukasz prostego wdrożenia, aby dowiedzieć się, jak można to zrobić, takie jak klasy pomocnika, który zwraca nową listę niezerową, można przyjrzeć się następującym kodem . Można również przyjąć typy ogólne, ze względu na prostotę użyłem tego samego typu kolekcji (jak w pytaniu) w klasie pomocnika.

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); 
    } 
} 
Powiązane problemy