Kanonik yol, özel bir Collector
uygulanıyordu.
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);
}
}
Sonra
short[] array=IntStream.range(0, 500).boxed().collect(ShortCollector.TO_ARRAY);
dezavantajı (Jenerik ilkel türde desteklemez gibi) Collector
s, sadece, böylece boxed()
başvurmak zorunda referans türleri için çalışır olduğunu ve bu gibi kullanabiliriz Koleksiyonerler, eleman sayısı hakkında bilgi kullanamazlar (eğer varsa). Böylece, ilkel veri akışı üzerinde performansın toArray()
'dan daha kötü olması muhtemeldir.
Yani, daha yüksek performans için çabalayan çözeltisi (bekar dişli durumda bu sınırlamak) aşağıdaki gibi görünecektir:
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();
}
Sen
short[] array=toShortArray(IntStream.range(0, 500));
Sen yapıyoruz gibi kullanabilir senin int yerine kısa kullanarak kendi hayatı karmaşık. Bu, herhangi bir performans veya bellek avantajı getirmez, ancak kodunuzun yazılmasını zorlaştırır. Yıllardır herhangi bir API'da kısa kullanmadım veya kısa bir süre görmedim. –
@JBNizet Bunu anlıyorum, ancak alan "short" türünde bir veritabanı sütununa karşılık geliyor (eski nedenlerden dolayı veritabanı şemasını değiştiremiyorum). 'Short' up-front'i depolayarak, veriyi veritabanına göndermeden önce son dakikada bir döküm hatası olasılığını önlüyorum. – Gili
Sorunu doğru bir şekilde anlıyorsunuz.akışları kitaplığı tasarımcıların o ShortStream vb unboxing jenerik ile birlikte çalışırlık ekleyerek ve, diyelim ki, bir 'Akışı' bunları diyebiliriz çünkü aynı zamanda işe yaramaz özel 'toShortArray()' yöntemleri ekleyerek değmez olduğuna karar verdi. –