流中的断言

Assertions in Streams

我知道我可以过滤流以仅获取那些不为空的元素,然后根据需要对它们进行处理。像这样:

myList.stream().filter(element -> element != null).doOtherThings...

有没有办法断言流函数中的元素不为空,以便它遍历所有元素,如果发现一个为空,则抛出异常?我一直在考虑以下内容:

myList.stream().assert(Objects::nonNull).doOtherThings...

使用类似

的东西
.map(Objects::requireNonNull)

您只需要应用一个会抛出异常的操作,否则会传递参数。

不过,除非有充分的理由不多次迭代列表,否则将检查和处理分开可能会更清楚:

if (myList.stream().anyMatch(Objects::isNull)) {
  throw ...
}
// Do things with list.

对于map方法我更喜欢用peek方法。我认为它比使用必须 return 一些值的 map 方法更具表现力。

    list.stream()
            .peek(Objects::requireNonNull)

然而,我认为很难理解的是,直到调用 collect() 时,流才会执行。这就是为什么很难使用流来执行这种条件逻辑。老实说,如果你想达到你想要的效果,你必须这样做。

list.stream()
            .peek(Objects::requireNonNull)
            .collect(Collectors.toList())
            .stream()
            .map(t -> do whatever ... )

已经有一些很好的建议了。让我补充一下。如果您想要的是 assert 语句中的断言,我想在代码中明确说明这一点,以指导 reader 了解我的目的。要断言您的原始列表不包含任何 nulls:

    assert ! myList.contains(null);

如果要在流管道下游某处检查断言,简单的方法是:

    assert myList.stream().map(this::transform).allMatch(Objects::nonNull);

如果您不想为断言创建单独的流,而是希望在现有流管道的中间进行断言,请使用例如:

        myList.stream()
                .peek(e -> { assert e != null; })
                .toArray();

你可能会担心peek的使用不是很好,这也是我最后提到这个选项的原因。 peek 被记录为存在“主要是为了支持调试”(从其上下文中引用),因此您可以说它与 assert 的目的相关,从而捍卫它在这种情况下的使用。