构建于Populating a List with a contiguous range of shorts我尝试生成一系列原始短裤。事实证明这比预期的要难得多。
Short[] range = IntStream.range(0, 500).mapToObj(value -> (short) value).toArray(Short[]::new)
工作但是:
short[] range = IntStream.range(0, 500).mapToObj(value -> (short) value).toArray(short[]::new)
生成了编译错误:
method toArray in interface Stream<T> cannot be applied to given types;
required: IntFunction<A[]>
found: short[]::new
reason: inference variable A has incompatible bounds
equality constraints: short
upper bounds: Object
where A,T are type-variables:
A extends Object declared in method <A>toArray(IntFunction<A[]>)
T extends Object declared in interface Stream
这似乎是两个问题的交集:
short
的实现。有什么想法吗?
答案 0 :(得分:0)
您可以考虑使用我的StreamEx库。它使用其他方法扩展了标准和流。我的库的目标之一是更好地与旧代码互操作。特别是它有IntStreamEx.toShortArray()
和IntStreamEx.of(short...)
:
short[] numbers = IntStreamEx.range(500).toShortArray();
short[] evenNumbers = IntStreamEx.of(numbers).map(x -> x*2).toShortArray();
请注意,它仍然是int
个数字的流。调用toShortArray()
时,它们会使用short
强制转换操作自动转换为(short)
类型,因此可以溢出。所以要小心使用。
还有IntStreamEx.toByteArray()
,IntStreamEx.toCharArray()
和DoubleStreamEx.toFloatArray()
。
答案 1 :(得分:0)
规范方式是实施自定义Collector
。
class ShortCollector {
public static Collector<Integer,ShortCollector,short[]> TO_ARRAY
=Collector.of(ShortCollector::new, ShortCollector::add,
ShortCollector::merge, c->c.get());
short[] array=new short[100];
int pos;
public void add(int value) {
int ix=pos;
if(ix==array.length) array=Arrays.copyOf(array, ix*2);
array[ix]=(short)value;
pos=ix+1;
}
public ShortCollector merge(ShortCollector c) {
int ix=pos, cIx=c.pos, newSize=ix+cIx;
if(array.length<newSize) array=Arrays.copyOf(array, newSize);
System.arraycopy(c.array, 0, array, ix, cIx);
return this;
}
public short[] get() {
return pos==array.length? array: Arrays.copyOf(array, pos);
}
}
然后你可以像
一样使用它short[] array=IntStream.range(0, 500).boxed().collect(ShortCollector.TO_ARRAY);
缺点是Collector
仅适用于引用类型(因为泛型不支持基本类型),因此您必须使用boxed()
并且收集器无法使用有关该数字的信息元素(如果有的话)。因此,性能可能远远低于原始数据流上的toArray()
。
因此,争取更高性能的解决方案(我将其限制为单线程案例)将如下所示:
public static short[] toShortArray(IntStream is) {
Spliterator.OfInt sp = is.spliterator();
long l=sp.getExactSizeIfKnown();
if(l>=0) {
if(l>Integer.MAX_VALUE) throw new OutOfMemoryError();
short[] array=new short[(int)l];
sp.forEachRemaining(new IntConsumer() {
int ix;
public void accept(int value) {
array[ix++]=(short)value;
}
});
return array;
}
final class ShortCollector implements IntConsumer {
int bufIx, currIx, total;
short[][] buffer=new short[25][];
short[] current=buffer[0]=new short[64];
public void accept(int value) {
int ix = currIx;
if(ix==current.length) {
current=buffer[++bufIx]=new short[ix*2];
total+=ix;
ix=0;
}
current[ix]=(short)value;
currIx=ix+1;
}
short[] toArray() {
if(bufIx==0)
return currIx==current.length? current: Arrays.copyOf(current, currIx);
int p=0;
short[][] buf=buffer;
short[] result=new short[total+currIx];
for(int bIx=0, e=bufIx, l=buf[0].length; bIx<e; bIx++, p+=l, l+=l)
System.arraycopy(buf[bIx], 0, result, p, l);
System.arraycopy(current, 0, result, p, currIx);
return result;
}
}
ShortCollector c=new ShortCollector();
sp.forEachRemaining(c);
return c.toArray();
}
您可以像
一样使用它short[] array=toShortArray(IntStream.range(0, 500));