2015-06-11 17 views
5

Populating a List with a contiguous range of shorts üzerinden bina İlkel bir şort dizisi oluşturmaya çalıştım. Bu beklenenden daha şaşırtıcı bir şekilde ortaya çıktı.Kısa bir [] akış kullanarak oluşturma

Short[] range = IntStream.range(0, 500).mapToObj(value -> (short) value).toArray(Short[]::new) çalıştı ama:

  1. ilkel Akış API'leri bir uygulama vermeyin:

    method toArray in interface Stream<T> cannot be applied to given types; 
        required: IntFunction<A[]> 
        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 <A>toArray(IntFunction<A[]>) 
        T extends Object declared in interface Stream 
    

    Bu iki problemi bir kesişme gibi görünüyor:

    short[] range = IntStream.range(0, 500).mapToObj(value -> (short) value).toArray(short[]::new) bir derleyici hata oluşturdu short s için. İlkel olmayan Akışlı API'lar, ilkel bir diziyi döndürmek için bir mekanizma sağlamaz gibi görünmemektedir.

Herhangi bir fikir?

+1

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. –

+0

@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

+2

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. –

cevap

1

Benim StreamEx kitaplığımı kullanmayı düşünebilirsiniz. Standart ve akışları ek yöntemlerle genişletir. Kitaplığımın hedeflerinden biri eski kodla daha iyi bir işbirliği. o int sayıların akışı hala olduğunu

short[] numbers = IntStreamEx.range(500).toShortArray(); 
short[] evenNumbers = IntStreamEx.of(numbers).map(x -> x*2).toShortArray(); 

Not: Özellikle bu IntStreamEx.toShortArray() ve IntStreamEx.of(short...) sahiptir. toShortArray() numaralı telefonu arayarak, (short) döküm işlemi kullanılarak otomatik olarak short türüne dönüştürülür, böylece taşma yapmak mümkündür. Bu yüzden dikkatli kullanın.

Ayrıca IntStreamEx.toByteArray(), IntStreamEx.toCharArray() ve DoubleStreamEx.toFloatArray() da vardır.

0

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)); 
İlgili konular