Kanoniczny sposób polegałby na wykonaniu niestandardowego 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);
}
}
Następnie można go używać jak
short[] array=IntStream.range(0, 500).boxed().collect(ShortCollector.TO_ARRAY);
Wadą jest to, że Collector
s działa tylko dla typów referencyjnych (jak rodzajowych nie obsługuje prymitywnych typów), więc trzeba uciekać się do boxed()
i kolektory nie mogą wykorzystywać informacji o liczbie elementów (jeśli są dostępne). Tak więc, wydajność może być znacznie gorsza niż w przypadku pierwotnego strumienia danych o wartości niższej niż toArray()
.
Więc rozwiązaniem dążenie do wyższej wydajności (ograniczam to do pojedynczego gwintowaną przypadku) będą wyglądać następująco:
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();
}
mogą go używać jak
short[] array=toShortArray(IntStream.range(0, 500));
Robisz swoje własne życie jest skomplikowane, używając krótkiego zamiast int. Nie przyniesie to żadnej wydajności ani pamięci, ale utrudni pisanie twojego kodu. Przez wiele lat nie używałem krótkiego kodu ani nie widziałem go w żadnym interfejsie API. –
@JBNizet Otrzymuję to, ale pole odpowiada kolumnie bazy danych typu 'short' (nie mogę zmienić schematu bazy danych ze względu na starsze wersje). Przechowując "short" z góry, zapobiegam możliwości wystąpienia błędu rzucania w ostatniej chwili, przed wysłaniem danych do bazy danych. – Gili
Prawidłowo rozumiesz problem.Projektanci bibliotek strumieniowych zdecydowali, że nie warto dodawać ShortStream itp., Unboxing nie współdziała z generycznymi, a dodanie specjalnych metod 'toShortArray()' również nie działałoby, ponieważ można by je wywoływać, powiedzmy, 'Stream'. –