【问题标题】:Is there an idiomatic way to assert a stream has only one element while yielding that element? [duplicate]有没有一种惯用的方法来断言流只有一个元素而产生该元素? [复制]
【发布时间】:2021-07-19 05:24:17
【问题描述】:

从这段代码开始:

public Thing thereCanBeOnlyOne(Stream<Thing> stream) {
  List<Thing> things = stream.collect(Collectors.toList());  
  if(things.size() != 1) {
    throw new IllegalArgumentException();
  }
  return things.get(0);
}

有没有更简洁的方式来表达方法体?

到目前为止我尝试了什么:

我阅读了Collectorreduce 的文档,但没有找到任何东西。

【问题讨论】:

  • .reduce(IDENTITY, (a, b) -&gt; { if(a.equals(IDENTITY)) return b; throw new IllegalArgumentException(); }); 但这取决于你的口味。
  • 取决于您的“惯用语”阈值:Guava 的 Iterables.getOnlyElement 将是我的首选。
  • 哦,番石榴也有MoreCollectors.onlyElement收集器。
  • @AndyTurner 肯定为此目的的外部库是矫枉过正?
  • @OleV.V.这不完全是一个正在工作的外部库;)当然,如果这就是你所需要的,那就太过分了。但是,如果您已经在使用它,那就太好了。存在其他库,ofc,因此您可以在您已经使用的库中找到等效的库。

标签: java java-stream


【解决方案1】:

如果您喜欢使用 Guava,请使用 MoreCollectors.onlyElement

public Thing thereCanBeOnlyOne(Stream<Thing> stream) {
  return stream.collect(MoreCollectors.onlyElement());
}

等价物很可能存在于其他常用库中;我只是熟悉番石榴。

【讨论】:

  • 这很好。我还发现.collect(Collectors.reducing((a, b) -&gt; null)); 是一个有趣的替代方案(返回 null 而不是抛出异常)。
【解决方案2】:

怎么样

public static Thing thereCanBeOnlyOne(Stream<Thing> stream) {
    Object[] array = null;
    if((array = stream.limit(2).toArray()).length != 1) {
            throw new IllegalArgumentException();
    }
    return (Thing)array[0];
}

在我看来,开销似乎更少。

【讨论】:

  • stream.limit(2).toArray() 在流中“很多”的情况下会更好。此外,null 赋值是多余的,只需在声明时从流中分配数组即可。
  • 不确定这里提到了哪些开销,但stream.limit(2).toArray(Thing[]::new) 可能会为您提供准确的类型
  • 我计算了调用收集器和创建列表的开销。如果我不先声明数组,由于范围问题,将找不到返回第一个元素。是的,我本可以只处理流然后检查长度,但我没有。我喜欢limit 的想法希望我能想到它:)
  • 也可以使用public static &lt;T&gt; T thereCanBeOnlyOne(Stream&lt;T&gt; stream)@SuppressedWarnings("unchecked") 使其更加通用。在这种情况下投射 Object to T 应该不会导致问题。
  • 这不再简洁明了。问题实际上与开销无关,但既然您提到它,当流在运行时预计仅包含 1 个元素时,开销是相同的。
猜你喜欢
  • 2022-12-07
  • 2014-11-18
  • 1970-01-01
  • 1970-01-01
  • 2018-06-30
  • 1970-01-01
  • 2017-03-13
  • 1970-01-01
  • 2015-08-04
相关资源
最近更新 更多