Java 8 streams and varargs

根据 Effective Java 2nd Ed,当你想要编写一个允许 varargs 但仍然强制你在编译时至少有一个元素的方法签名时,你应该这样编写方法签名:

public void something(String required, String ... additional) {
    //... do what you want to do
}

如果我想流式传输所有这些元素,我一直在做这样的事情:

public void something(String required, String ... additional) {
    Stream<String> allParams =
        Stream.concat(Stream.of(required), Stream.of(additional));
    //... do what you want to do
}

这感觉真的很不优雅和浪费,特别是因为我正在创建一个1的流并将其与另一个流连接。有没有更清洁的方法可以做到这一点?


答案 1

这是一种无需创建两个的方法,尽管您可能不喜欢它。Streams

Stream.Builder<String> builder = Stream.<String>builder().add(required);
for (String s : additional) {
  builder.add(s);
}

Stream<String> allParams = builder.build();

答案 2

组合的流没有错。这些对象是轻量级的,因为它们仅引用源数据,但不像数组内容那样复制数据。这种轻量级对象的成本可能只有在实际有效载荷也非常小的情况下才有意义。此类方案可以使用专门的、语义上等效的重载来处理:

public void something(String required, String ... additional) {
    somethingImpl(Stream.concat(Stream.of(required), Stream.of(additional)));
}
public void something(String required) {
    somethingImpl(Stream.of(required));
}
public void something(String required, String second) {
    somethingImpl(Stream.of(required, second));
}
private void somethingImpl(Stream<String> allParams) {
    //... do what you want to do
}

因此,在只有一个参数的情况下,您不仅可以保存实例,还可以保存varargs数组(类似于 的重载)。这是一种常见的模式,例如,请参阅重载。StreamStream.ofEnumSet.of

但是,在很多情况下,即使是这些简单的重载也不是必需的,并且可能被认为是过早优化(像JRE这样的库提供了它们,因为如果需要,应用程序开发人员就不可能添加它们)。如果 是应用程序的一部分,而不是库的一部分,则不应添加它们,除非探查器告诉您该参数处理存在瓶颈。something