Reputation: 449
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;
Upvotes: 6
Views: 3746
Reputation: 11740
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());
}
Upvotes: 8
Reputation: 6686
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
Upvotes: 5
Reputation: 3453
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.
Upvotes: 4