使用流生成short
在使用连续的短裤范围填充列表的基础上,我尝试生成一组原始短裤。 事实certificate这比预期的要难得多。
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 cannot be applied to given types; required: IntFunction 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 toArray(IntFunction) T extends Object declared in interface Stream
这似乎是两个问题的交集:
- 原始Stream API不提供
short
s的实现。 - 非原始Stream API似乎不提供返回基本数组的机制。
有任何想法吗?
您可以考虑使用我的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)
toShortArray()
转换操作自动转换为short
类型,因此可以溢出。 所以要小心使用。
还有IntStreamEx.toByteArray()
, IntStreamEx.toCharArray()
和DoubleStreamEx.toFloatArray()
。
规范的方法是实现自定义Collector
。
class ShortCollector { public static Collector 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
然后你可以像使用它一样
short[] array=IntStream.range(0, 500).boxed().collect(ShortCollector.TO_ARRAY);
缺点是Collector
仅适用于引用类型(因为Generics不支持基本类型),因此您必须求助于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
你可以像使用它一样
short[] array=toShortArray(IntStream.range(0, 500));