How to map and collect primitive return type using Java 8 Stream

亡梦爱人 提交于 2020-05-10 20:08:20

问题


I am new in Java 8 streams and I am wondering if there is way to perform forEach/map call on method returning a byte and accepting an int as parameter.

Example:

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[]
   }
}

As you may guess, the getBytes method not working. "int[] cannot be converted to int"Probably somewhere is missing foreach, but personally cant figure it out.

However, this is working, old-fashioned approach which I would like to rewrite as Stream.

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

回答1:


You can write your own Collector and build your byte[] with an ByteArrayOutputStream:

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);
  }
}

And use it:

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



回答2:


If you are open to using a third-party library, Eclipse Collections has collections support for all eight Java primitive types. The following should work:

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

Updated: I changed the original code to be lazy.

Note: I am a committer for Eclipse Collections




回答3:


There's no good way to do this with streams. Any implementation using collect is going to rely on appending elements, which gets really ugly for arrays. This is as close as you're going to get:

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

The IntStream.toArray method has a ton of overhead involving internal "node" objects and array concatenation, so this is also much less efficient. I recommend sticking with the old for loop.



来源:https://stackoverflow.com/questions/44708532/how-to-map-and-collect-primitive-return-type-using-java-8-stream

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!