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

我试着用这样的循环

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

但这并不好。 任何人都可以build议我一个更好的解


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

While循环,For循环和Iterator性能testing

尝试:

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

阅读Java API 。 代码将抛出java.lang.UnsupportedOperationException为不可变列表(如使用Arrays.asList创build); 看到这个答案更多的细节。

到2015年,这是最好的方法(Java 8):

 tourists.removeIf(Objects::isNull); 

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

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

如果你在Arrays.asList中使用它,它会抛出UnsupportedException ,因为它给你不可变的拷贝,所以它不能被修改。 看下面的代码。 它创build可变的副本,不会抛出任何exception。

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

效率不高,但很短

 while(tourists.remove(null)); 

如果你喜欢不可变的数据对象,或者你不想破坏input列表,你可以使用Guava的谓词。

 ImmutableList.copyOf(Iterables.filter(tourists, Predicates.notNull())) 
  for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) { if (itr.next() == null) { itr.remove(); } } 

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

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

Objects类具有一个nonNull Predicate ,可用于filter

例如:

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

这是从列表中删除默认空值的简单方法

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

否则将String值“null”从arraylist中移除

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

使用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 – stream

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

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

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

我使用stream接口和stream操作collect和一个辅助方法来生成一个新的列表。

 tourists.stream().filter(this::isNotNull).collect(Collectors.toList()); private <T> boolean isNotNull(final T item) { return item != null; } 

在Java之前,你应该使用:

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

Post-Java 8使用:

 tourists.removeIf(Objects::isNull); 

这里的原因是时间复杂性。 数组的问题是删除操作可能需要O(n)个时间才能完成。 真的在Java中,这是一个被移动的剩余元素的数组副本,以replace空白点。 这里提供的许多其他解决scheme将触发此问题。 前者在技术上是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)操作。

唯一可能会更快的是,如果从两端迭代列表,并且发现空值,则将其值设置为等于最后find的值,然后减小该值。 并迭代,直到两个值匹配。 你会弄乱顺序,但会大大减less你设定的值与你独自留下的值。 这是一个很好的方法知道,但不会在这里帮助很多,因为.set()基本上是免费的,但是这种删除forms是一个有用的工具。


 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()来执行删除操作。 你可以毫不夸张地说,整个项目之间的集合与价值和项目与空值sorting和修剪结束在较less的时间。 事实上,所有破碎的都是如此。 至less在理论上,实际的system.arraycopy实际上并不是N操作。 理论上讲,理论和实践是一回事; 实际上他们不是。

使用Java 8,可以使用stream,并行stream和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] 

并行stream将利用可用的处理器,并将加快合理大小列表的处理。 在使用stream之前总是build议进行基准testing。