我尝试这样的循环
// ArrayList tourists
for (Tourist t : tourists) {
if (t != null) {
t.setId(idForm);
}
}
但这不是很好。谁能建议我一个更好的解决方案?
一些有用的基准可以做出更好的决策:
我尝试这样的循环
// ArrayList tourists
for (Tourist t : tourists) {
if (t != null) {
t.setId(idForm);
}
}
但这不是很好。谁能建议我一个更好的解决方案?
一些有用的基准可以做出更好的决策:
Answers:
尝试:
tourists.removeAll(Collections.singleton(null));
阅读Java API。该代码将抛出java.lang.UnsupportedOperationException
不可变的列表(例如使用创建的Arrays.asList
);有关更多详细信息,请参见此答案。
List.removeAll()
为n ^ 2。只是说。
O(n)
给我两个ArrayList
和LinkedList
。
截至2015年,这是最好的方法(Java 8):
tourists.removeIf(Objects::isNull);
注意:该代码将java.lang.UnsupportedOperationException
针对固定大小的列表(例如使用Arrays.asList创建的列表)抛出,包括不可变列表。
removeIf
是更快,但这只是一个猜测。
Arrays.asList
不是一成不变的。它是固定大小的。
list.removeAll(Collections.singleton(null));
如果在Arrays.asList上使用它,它将抛出UnsupportedException,因为它为您提供了不可变的副本,因此无法对其进行修改。参见下面的代码。它创建可变副本,并且不会引发任何异常。
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));
for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) {
if (itr.next() == null) { itr.remove(); }
}
removeAll(..null..)
。谢谢!
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()。并迭代列表。当它到达空值时,它只是简单地将读取位置迭代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)操作。
唯一可能更快的方法是,如果从两端迭代列表,当发现空值时,请将其值设置为等于在末尾找到的值,然后递减该值。并迭代直到两个值匹配。您会弄乱顺序,但是会大大减少您设置的值与单独留下的值的数量。这是一个很好的方法,但是由于.set()基本上是免费的,因此在这里无济于事,但是这种删除形式对于您的工作场所是有用的工具。
for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) {
if (itr.next() == null) { itr.remove(); }
}
尽管这似乎足够合理,但是迭代器上的.remove()内部调用:
ArrayList.this.remove(lastRet);
这也是remove中的O(n)操作。如果您关心速度,它将执行System.arraycopy(),这又不是您想要的。这使其为n ^ 2。
还有:
while(tourists.remove(null));
是O(m * n ^ 2)。在这里,我们不仅迭代列表。每次匹配null时,我们都会重复整个列表。然后,我们执行n / 2(平均)操作来执行System.arraycopy()来执行删除操作。从字面上看,您可以对具有值的项目和具有空值的项目之间的整个集合进行排序,并以更少的时间修剪结尾。实际上,对于所有损坏的对象都是如此。至少从理论上讲,实际的system.arraycopy实际上不是N操作。理论上,理论和实践是同一回事。实际上不是。
使用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-流
这是从arraylist中删除默认null值的简单方法
tourists.removeAll(Arrays.asList(null));
否则,将字符串值“ null”从arraylist中删除
tourists.removeAll(Arrays.asList("null"));
使用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]
并行流将利用可用的处理器,并为合理大小的列表加快处理速度。始终建议在使用流之前先进行基准测试。
Iterator
?挖java-doc。download.oracle.com/javase/6/docs/api/java/util/…–