我试着像那样绕圈
// ArrayList tourists for (Tourist t : tourists) { if (t != null) { t.setId(idForm); } }
但这并不好。谁能给我一个更好的解决办法?
一些有用的基准可以帮助你做出更好的决定:
While循环,For循环和迭代器性能测试
for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) { if (itr.next() == null) { itr.remove(); } }
试一试:
tourists.removeAll(Collections.singleton(null));
读取Java API。代码将为不可变列表抛出java.lang.UnsupportedOperationException(例如用Arrays.asList创建的列表);更多细节见这个答案。
java.lang.UnsupportedOperationException
Arrays.asList
效率不高,但时间短
while(tourists.remove(null));
我摆弄了一下,发现trimToSize()似乎可以工作。我是在Android平台上工作,所以可能会有所不同。
有一种简单的方法可以从collection中删除所有null值。必须将包含null的集合作为参数传递给removeAll()方法
collection
null
removeAll()
List s1=new ArrayList(); s1.add(null); yourCollection.removeAll(s1);
如果你更喜欢不可变的数据对象,或者你不想破坏输入列表,你可以使用Guava的谓词。
ImmutableList.copyOf(Iterables.filter(tourists, Predicates.notNull()))
list.removeAll(Collections.singleton(null));
如果你在数组上使用它,它将抛出UnsupportedException。asList,因为它给你不可变的副本,所以它不能修改。请参阅下面的代码。它创建可变的副本,并且不会抛出任何异常。
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()]); }
这是从数组列表中删除默认空值的简单方法
tourists.removeAll(Arrays.asList(null));
从数组列表中删除字符串值“null”
tourists.removeAll(Arrays.asList("null"));
我们可以使用迭代器for the same删除所有空值。
Iterator<Tourist> itr= tourists.iterator(); while(itr.hasNext()){ if(itr.next() == null){ itr.remove(); } }
截至2015年,这是最好的方法(Java 8):
tourists.removeIf(Objects::isNull);
注意:此代码将为固定大小的列表抛出java.lang.UnsupportedOperationException(例如使用Arrays.asList创建的列表),包括不可变列表。
我使用流接口和流操作收集以及一个helper方法来生成一个新列表。
tourists.stream().filter(this::isNotNull).collect(Collectors.toList()); private <T> boolean isNotNull(final T item) { return item != null; }
Objects类有一个nonNull Predicate,可以与filter一起使用。
Objects
nonNull
Predicate
filter
例如:
tourists.stream().filter(Objects::nonNull).collect(Collectors.toList());
在Java 8中,你可以使用stream()和filter()来做到这一点
stream()
filter()
tourists = tourists.stream().filter(t -> t != null).collect(Collectors.toList())
或
tourists = tourists.stream().filter(Objects::nonNull).collect(Collectors.toList())
更多信息:Java 8 - Streams
在java 8之前,你应该使用:
java 8后使用:
原因在于时间的复杂性。数组的问题是删除操作可能需要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)操作。
虽然这看起来很合理,但迭代器上的.remove()在内部调用:
ArrayList.this.remove(lastRet);
同样是O(n)操作。它执行system。arraycopy()如果你关心速度,这也不是你想要的。它是n²。
还有:
使用Java 8可以使用流、并行流和removeIf方法以各种方式执行此操作:
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]
并行流将利用可用的处理器,并将加快合理大小列表的处理速度。在使用流之前进行基准测试总是明智的。
类似于@Lithium的答案,但不抛出“列表可能不包含类型null”错误:
list.removeAll(Collections.<T>singleton(null));
List<String> colors = new ArrayList<>( Arrays.asList("RED", null, "BLUE", null, "GREEN")); // using removeIf() + Objects.isNull() colors.removeIf(Objects::isNull);
我主要用这个:
但是在我学习了Java 8之后,我改用了这个:
List.removeIf(Objects::isNull);