在Java中,从字符串列表中删除空元素

73
在Java中,我有一个字符串的ArrayList,例如:
[,Hi, ,How,are,you]

我想要移除掉空和null元素,应该怎样修改代码才能达到以下效果:

[Hi,How,are,you]
14个回答

103
List<String> list = new ArrayList<String>(Arrays.asList("", "Hi", null, "How"));
System.out.println(list);
list.removeAll(Arrays.asList("", null));
System.out.println(list);

输出:

[, Hi, null, How]
[Hi, How]

9
调用java.util.AbstractList.remove()方法时,我收到了UnsupportedOperationException异常。 - shkschneider
2
我重新做了一遍,现在它可以工作了。我的错。此致。 - shkschneider
我们需要从utilawt库中导入吗? - Lakshya Goyal
有没有办法将列表转换回数组?并且我们可以保持与之前相同的位置数吗?它只会将所有空格移动到末尾? - Lakshya Goyal
@LakshyaGoyal 他们说谷歌是你的朋友 - https://www.google.com/search?q=arraylist+to+array - Sufian
它会抛出UnsupportedOperationException,不确定为什么对其他人有效? - Derrick

50

虽然回答已经很晚了,但是您也可以使用 Collections.singleton

List<String> list = new ArrayList<String>(Arrays.asList("", "Hi", null, "How"));
// in one line
list.removeAll(Arrays.asList("", null))

// separately
list.removeAll(Collections.singleton(null));
list.removeAll(Collections.singleton(""));

1
它会抛出UnsupportedOperationException,不确定它为什么对其他人有效。 - Derrick
2
@Derick 如果你不用 new ArrayList<String> 包装 Arrays.asList,那么它会抛出 UnsupportedOperationException 异常。因为 Arrays.asList 不能被结构性修改,所以无法执行 removeIf 操作。 - Deepthi

29

现在我们有Java 8 lambda表达式,可以采用另一种方式来实现此操作。

arrayList.removeIf(item -> item == null || "".equals(item));

2
使用Guava,您可以执行arrayList.removeIf(Strings::isNullOrEmpty); - shmosel
2
或者使用Apache Commons arrayList.removeIf(StringUtils::isEmpty); - Andrew Mairose
或者,如果您想删除仅包含空格字符的条目,则可以使用 arrayList.removeIf(StringUtils::isBlank); - Andrew Mairose
顺便说一句,检查 null 值时使用 Yoda 比较是没有意义的。 - shmosel
1
使用Java 11的语法,删除ArrayList中所有空白字符串。 - Oozeerally

9
  1. If you were asking how to remove the empty strings, you can do it like this (where l is an ArrayList<String>) - this removes all null references and strings of length 0:

    Iterator<String> i = l.iterator();
    while (i.hasNext())
    {
        String s = i.next();
        if (s == null || s.isEmpty())
        {
            i.remove();
        }
    }
    
  2. Don't confuse an ArrayList with arrays, an ArrayList is a dynamic data-structure that resizes according to it's contents. If you use the code above, you don't have to do anything to get the result as you've described it -if your ArrayList was ["","Hi","","How","are","you"], after removing as above, it's going to be exactly what you need - ["Hi","How","are","you"].

    However, if you must have a 'sanitized' copy of the original list (while leaving the original as it is) and by 'store it back' you meant 'make a copy', then krmby's code in the other answer will serve you just fine.


正如你所提到的,ArrayList上没有零参数的神奇删除方法。 - Kerem Baydoğan
1
请仔细查看 - remove() 是在 Iterator 上调用的,而不是在 ArrayList 上。 - no.good.at.coding
如果您在 ArrayList 上调用了 remove() 方法,则返回您的答案。 - Kerem Baydoğan
你可以调用 remove("") 来删除所有空字符串。但是对于只有空格的字符串,这种方法不起作用。 - squawknull
@krmby 已编辑,谢谢。@squaknull 很好,我没想到(尽管你仍然需要在循环中执行它)。这取决于 OP 所指的“空”是什么意思 - 我已经放置了一个免责声明,表明此循环仅会删除所有 null 和空字符串。 - no.good.at.coding

9

在过滤器中,Lambda 可以被方法引用所代替: filter(StringUtils::isNotBlank) - Aldis

7
我来翻译一下:这句话的意思是“我要在这里放下这个小提示”。
Stream.of("", "Hi", null, "How", "are", "you")
  .filter(t -> !Strings.isNullOrEmpty(t))
  .collect(ImmutableList.toImmutableList());

我从心底希望 Java 有一个“filterNot”方法。

什么是字符串 - 是Guava吗? - Woodchuck
@JWoodchuck 是的,我相信是这样的。 - Sam Berry
1
我已经有一段时间没有回答这个问题了,但看起来它是Guava。 - Sam Berry

5
有几种方法可供选择:
  1. 迭代列表,并对要删除的列表元素调用Iterator.remove()。这是最简单的方法。

  2. 重复调用List.remove(Object)。这也很简单,但性能最差……因为你会反复扫描整个列表。(然而,这可能是一个选项,适用于其迭代器不支持remove的可变列表……由于某种原因。)

  3. 创建一个新列表,遍历旧列表,将要保留的元素添加到新列表中。

  4. 如果不能返回新列表,则按照第3种方法操作,然后清除旧列表并使用addAll将新列表的元素添加回去。

哪种方法最快取决于原始列表的类别、大小和需要删除的元素数量。以下是一些因素:

  • 对于ArrayList,每个单独的remove操作都是O(N),其中N是列表大小。使用Iterator.remove()方法(或ArrayList.remove(element)方法)从大型ArrayList中删除多个元素是昂贵的。

    相比之下,LinkedListIterator.remove方法是O(1)

  • 对于ArrayList,创建和复制列表是O(N)的,相对便宜,特别是如果你可以确保目标列表的容量足够大(但不要太大)。

    相比之下,创建并复制到LinkedList也是O(N),但要更昂贵。

所有这些都加起来形成了一个相当复杂的决策树。如果列表很小(比如10个或更少的元素),你可能可以使用上述任何一种方法。如果列表可能很大,你需要权衡列表大小和预期移除数量列表中所有问题。(否则,你可能会得到二次性能。)


4
  • 这段代码可以顺利编译并运行。
  • 它没有使用迭代器,因此更易读。
  • list是你的集合。
  • result是经过过滤处理的(不包含null和空值)。

public static void listRemove() {
    List<String> list = Arrays.asList("", "Hi", "", "How", "are", "you");
    List<String> result = new ArrayList<String>();

    for (String str : list) {
        if (str != null && !str.isEmpty()) {
            result.add(str);
        }
    }

    System.out.println(result);
}

3
因为 str 可能是 null,所以会抛出一个 java.lang.NullPointerException - no.good.at.coding

3
如果你从上面的回答中使用其中一个并且你的列表是由Arrays.asList()创建的,而且你收到了一个UnsupportedOperationException,那是因为你无法编辑这样的List
要解决问题,需要在new LinkedList<String>()中包装Arrays.asList()
    List<String> list = new LinkedList<String>(Arrays.asList(split));

以下内容源自这个答案


2
关于Andrew Mairose的评论 - 尽管这是一个好的解决方案,但我想补充说明这个解决方案无法在固定大小的列表上使用。
您可以尝试这样做:
Arrays.asList(new String[]{"a", "b", null, "c", "    "})
    .removeIf(item -> item == null || "".equals(item));

但是你可能会遇到一个java.util.AbstractList.removeUnsupportedOperationException(因为asList返回的是一个不可调整大小的列表)。

另一种解决方案可能是这样的:

List<String> collect =
    Stream.of(new String[]{"a", "b", "c", null, ""})
        .filter(item -> item != null && !"".equals(item))
        .collect(Collectors.toList());

这将产生一个漂亮的字符串列表 :-)

不错的观点,但是OP确实说它是一个ArrayList,而ArrayList并不是固定大小的。 - Andrew Mairose

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接