【问题标题】:How to map and collect primitive return type using Java 8 Stream如何使用 Java 8 Stream 映射和收集原始返回类型
【发布时间】:2017-11-26 06:32:01
【问题描述】:

我是 Java 8 流的新手,我想知道是否有办法对返回 byte 并接受 int 作为参数的方法执行 forEach/map 调用。

例子:

public class Test {
   private byte[] byteArray; // example of byte array

   public byte getByte(int index) {
      return this.byteArray[index];
   }

   public byte[] getBytes(int... indexes) {
      return Stream.of(indexes)
             .map(this::getByte) // should return byte
             .collect(byte[]::new); // should return byte[]
   }
}

您可能已经猜到了,getBytes 方法不起作用。 "int[] cannot be converted to int"可能某处缺少foreach,但个人想不通。

但是,这是一种可行的老式方法,我想将其重写为 Stream。

byte[] byteArray = new byte[indexes.length];
for ( int i = 0; i < byteArray.length; i++ ) {
   byteArray[i] = this.getByte( indexes[i] );
}
return byteArray;

【问题讨论】:

  • 不。没有ByteStream。但是由于字对齐,byte 无论如何都不太可能是 8 位。您基于循环的方法简单、清晰且惯用 - 为什么要更改它?
  • 感谢您的回答。这可能是我无法使其工作的原因。然而,难道就没有办法做到这一点吗?使用类型转换或编写我自己的 ByteStream?

标签: java arrays java-8 byte java-stream


【解决方案1】:

您可以编写自己的Collector 并使用ByteArrayOutputStream 构建您的byte[]

final class MyCollectors {

  private MyCollectors() {}

  public static Collector<Byte, ?, byte[]> toByteArray() {
    return Collector.of(ByteArrayOutputStream::new, ByteArrayOutputStream::write, (baos1, baos2) -> {
      try {
        baos2.writeTo(baos1);
        return baos1;
      } catch (IOException e) {
        throw new UncheckedIOException(e);
      }
    }, ByteArrayOutputStream::toByteArray);
  }
}

并使用它:

public byte[] getBytes(int... indexes) {
  return IntStream.of(indexes).mapToObj(this::getByte).collect(MyCollectors.toByteArray());
}

【讨论】:

    【解决方案2】:

    如果您愿意使用第三方库,Eclipse Collections 具有对所有八种 Java 原始类型的集合支持。以下应该有效:

    public byte[] getBytes(int... indexes) {
        return IntLists.mutable.with(indexes)
                .asLazy()
                .collectByte(this::getByte)
                .toArray();
    }
    

    更新:我把原来的代码改成懒惰了。

    注意:我是 Eclipse Collections 的提交者

    【讨论】:

      【解决方案3】:

      对于流没有很好的方法来做到这一点。任何使用collect 的实现都将依赖于附加元素,这对于数组来说真的很难看。这是您将要获得的最接近的结果:

      int[] ints = IntStream.of(indexes)
              .map(this::getByte) // upcast to int, still IntStream
              .toArray(); // specialized collect
      

      IntStream.toArray 方法有大量开销,涉及内部“节点”对象和数组连接,因此效率也低得多。我建议坚持使用旧的 for 循环。

      【讨论】:

      • 感谢您的回答和解释。这只是一个例子,但我想我会坚持使用 for 循环。
      猜你喜欢
      • 2019-04-19
      • 1970-01-01
      • 2017-04-19
      • 1970-01-01
      • 1970-01-01
      • 2018-10-14
      • 2017-09-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多