Канонический путь будет осуществлять пользовательский 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
s работает только для ссылочных типов (как Дженерики не поддерживает примитивные типы), таким образом, вы должны прибегнуть к 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));
вы делаете ваш собственная жизнь осложняется использованием коротких, а не int. Это не принесет никакой пользы производительности или памяти, но сделает ваш код сложнее писать. В течение многих лет я не использовал короткую или короткую информацию в любом API. –
@JBNizet Я получаю это, но поле соответствует столбцу базы данных типа 'short' (я не могу изменить схему базы данных по устаревшим причинам). Сохраняя «короткий» фронт, я предотвращаю возможность ошибки кастинга в последнюю минуту, прежде чем отправлять данные в базу данных. – Gili
Вы правильно поняли проблему.Дизайнеры библиотек потоков решили, что не стоит добавлять ShortStream и т. Д., Unboxing не взаимодействует с дженериками, и добавление специальных методов 'toShortArray()' также не будет работать, потому что вы могли бы называть их, скажем, 'Stream'. –