如何从ArrayList或String数组中删除所有null元素?

时间:2011-01-27 17:21:07

标签: java performance loops for-loop arraylist

我尝试使用这样的循环

// ArrayList tourists

for (Tourist t : tourists) {
    if (t != null) {     
        t.setId(idForm); 
    }   
}

但这并不好。谁能建议我一个更好的解决方案?


做出更好决策的一些有用的基准:

While loop, For loop and Iterator Performance Test

18 个答案:

答案 0 :(得分:350)

尝试:

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

阅读Java API。代码将为不可变列表抛出java.lang.UnsupportedOperationException(例如使用Arrays.asList创建);有关详细信息,请参阅this answer

答案 1 :(得分:97)

截至2015年,这是最好的方式(Java 8):

tourists.removeIf(Objects::isNull);

注意:此代码将为固定大小的列表(例如使用Arrays.asList创建)抛出java.lang.UnsupportedOperationException,包括不可变列表。

答案 2 :(得分:45)

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

如果您在Arrays.asList上使用它,它将抛出 UnsupportedException ,因为它会为您提供不可变副本,因此无法修改它。见下面的代码。它会创建 Mutable 副本,不会抛出任何异常。

public static String[] clean(final String[] v) {
    List<String> list = new ArrayList<String>(Arrays.asList(v));
    list.removeAll(Collections.singleton(null));
    return list.toArray(new String[list.size()]);
}

答案 3 :(得分:18)

效率不高,但很短

while(tourists.remove(null));

答案 4 :(得分:18)

如果您更喜欢不可变数据对象,或者您只是不想破坏输入列表,则可以使用Guava的谓词。

ImmutableList.copyOf(Iterables.filter(tourists, Predicates.notNull()))

答案 5 :(得分:7)

 for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) {
      if (itr.next() == null) { itr.remove(); }
 }

答案 6 :(得分:3)

有一种简单的方法可以从null中删除所有collection值。您必须将包含null的集合作为参数传递给removeAll()方法

List s1=new ArrayList();
s1.add(null);

yourCollection.removeAll(s1);

答案 7 :(得分:3)

Objects班级有nonNull Predicate,可与filter一起使用。

例如:

tourists.stream().filter(Objects::nonNull).collect(Collectors.toList());

答案 8 :(得分:3)

使用Java 8,您可以使用stream()filter()

执行此操作
tourists = tourists.stream().filter(t -> t != null).collect(Collectors.toList())

tourists = tourists.stream().filter(Objects::nonNull).collect(Collectors.toList())

了解详情: Java 8 - Streams

答案 9 :(得分:3)

Pre-Java 8你应该使用:

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

使用Java 8之后:

tourists.removeIf(Objects::isNull);

这里的原因是时间复杂性。数组的问题是删除操作可能需要O(n)时间才能完成。实际上在Java中,这是要移动的剩余元素的数组副本以替换空白点。此处提供的许多其他解决方案将触发此问题。前者在技术上是O(n * m),其中m是1,因为它是单例null:所以O(n)

你应该删除所有的单例,在内部它会执行一个具有读取位置和写入位置的batchRemove()。并迭代列表。当它达到null时,它只是将读取位置迭代1.当它们相同时它会通过,当它们不同时,它会继续沿着复制值移动。然后在结束时修剪尺寸。

它在内部有效地做到了这一点:

public static <E> void removeNulls(ArrayList<E> list) {
    int size = list.size();
    int read = 0;
    int write = 0;
    for (; read < size; read++) {
        E element = list.get(read);
        if (element == null) continue;
        if (read != write) list.set(write, element);
        write++;
    }
    if (write != size) {
        list.subList(write, size).clear();
    }
}

您可以明确看到的是O(n)操作。

唯一可能更快的是,如果从两端迭代列表,并且当找到null时,将其值设置为等于最后找到的值,并递减该值。并迭代,直到两个值匹配。你搞砸了订单,但会大大减少价值 你设置与你独自留下的人。这是一个很好的方法,但在这里帮助不大,因为.set()基本上是免费的,但这种形式的删除对你来说是一个很有用的工具。

for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) {
      if (itr.next() == null) { itr.remove(); }
 }

虽然这看起来足够合理,但迭代器上的.remove()内部调用:

ArrayList.this.remove(lastRet);

这又是删除中的O(n)操作。如果您关心速度,它会执行System.arraycopy(),这也不是您想要的。这使它成为n ^ 2.

还有:

while(tourists.remove(null));

哪个是O(m * n ^ 2)。在这里,我们不仅迭代列表。我们重复整个列表,每次匹配null。然后我们进行n / 2(平均)操作来执行System.arraycopy()来执行删除。 您可以完全按照字面意思,使用值和具有空值的项目对项目之间的整个集合进行排序,并在更短的时间内修剪结尾。事实上,对于所有破碎的人来说都是如此。至少在理论上,实际的system.arraycopy实际上并不是N操作。从理论上讲,理论和实践是一回事;实际上他们不是。

答案 10 :(得分:2)

这是从arraylist

中删除默认空值的简便方法
     tourists.removeAll(Arrays.asList(null));  

否则字符串值“null”从arraylist中删除

       tourists.removeAll(Arrays.asList("null"));  

答案 11 :(得分:1)

我玩弄了这个并发现trimToSize()似乎有效。我正在Android平台上工作,所以可能会有所不同。

答案 12 :(得分:1)

我们可以使用迭代器来删除所有空值。

Iterator<Tourist> itr= tourists.iterator();
while(itr.hasNext()){
    if(itr.next() == null){
        itr.remove();
    }
}

答案 13 :(得分:1)

我将流接口与流操作收集和辅助方法一起使用以生成新列表。

tourists.stream().filter(this::isNotNull).collect(Collectors.toList());

private <T> boolean isNotNull(final T item) {
    return  item != null;
}

答案 14 :(得分:1)

主要是我在用这个:

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

但是在我学习Java 8之后,我切换到了这个地方

List.removeIf(Objects::isNull);

答案 15 :(得分:0)

使用 Java 8 ,可以使用流,并行流和removeIf方法以各种方式执行此操作:

List<String> stringList = new ArrayList<>(Arrays.asList(null, "A", "B", null, "C", null));
List<String> listWithoutNulls1 = stringList.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toList()); //[A,B,C]
List<String> listWithoutNulls2 = stringList.parallelStream()
                .filter(Objects::nonNull)
                .collect(Collectors.toList()); //[A,B,C]
stringList.removeIf(Objects::isNull); //[A,B,C]

并行流将利用可用的处理器,并将加速合理大小的列表的过程。在使用流之前始终建议进行基准测试。

答案 16 :(得分:0)

与@Lithium答案类似,但不会抛出&#34; List可能不包含类型null&#34;错误:

   list.removeAll(Collections.<T>singleton(null));

答案 17 :(得分:0)

List<String> colors = new ArrayList<>(
Arrays.asList("RED", null, "BLUE", null, "GREEN"));
// using removeIf() + Objects.isNull()
colors.removeIf(Objects::isNull);
相关问题