Il modo canonico sarebbe l'implementazione di una personalizzata 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);
}
}
Allora si potrebbe utilizzare come
short[] array=IntStream.range(0, 500).boxed().collect(ShortCollector.TO_ARRAY);
Lo svantaggio è che Collector
s funziona solo per i tipi di riferimento (come Generics non supporta i tipi primitivi), quindi si deve ricorrere a boxed()
e i collezionisti non possono utilizzare le informazioni sul numero di elementi (se mai disponibili). Pertanto, è probabile che le prestazioni siano molto peggiori di toArray()
in un flusso di dati primitivo.
Quindi, una soluzione lotta per prestazioni più elevate (I limitare questo per il caso filettato singolo) sarà simile a questa:
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();
}
lo si può utilizzare come
short[] array=toShortArray(IntStream.range(0, 500));
Stai facendo la vostra la propria vita complicata usando short invece di int. Ciò non porterà alcun vantaggio in termini di prestazioni o memoria, ma renderà il tuo codice più difficile da scrivere. Non ho usato un breve, o visto un corto in qualsiasi API, per anni. –
@JBNizet Viene visualizzato, ma il campo corrisponde a una colonna del database di tipo 'short' (non riesco a modificare lo schema del database per motivi legacy). Memorizzando 'short' up-front prevengo la possibilità di un errore di casting all'ultimo minuto, prima di inviare i dati al database. – Gili
Hai capito correttamente il problema.I progettisti della libreria dei flussi hanno deciso che non valeva la pena di aggiungere ShortStream ecc., L'unboxing non interagisce con i generici e l'aggiunta di speciali metodi 'toShortArray()' non funzionerebbe anche perché potresti chiamarli su, ad esempio, 'Stream '. –