2015-09-08 8 views
19

Java 8 bietet Stream<T> Spezialisierungen für double, int und long: DoubleStream, IntStream und LongStream sind. Ich konnte jedoch keine Entsprechung für byte in the documentation finden.Gibt es in Java 8 eine ByteStream-Klasse?

Bietet Java 8 eine ByteStream Klasse?

+2

http://stackoverflow.com/questions/22918847/why-are-new-java-util-arrays-methods-in-java-8-not-overloaded-for-all-the-primit – assylias

Antwort

23

Nein, es existiert nicht. Tatsächlich wurde es explizit nicht implementiert, um die Stream-API mit Tonnen von Klassen für jeden primitiven Typ nicht zu überladen.

a mail von Brian Goetz in der OpenJDK-Mailingliste Zitiert:  

Kurze Antwort: nein.

Es lohnt sich nicht, weitere 100K + JDK Fußabdruck jeweils für diese Formen , die fast nie verwendet werden. Und wenn wir diese hinzufügen würden, würde jemand kurz, float oder boolean verlangen.

Anders gesagt, wenn Leute darauf bestanden, dass wir alle primitiven Spezialisierungen hätten, hätten wir keine primitiven Spezialisierungen. Welcher wäre schlechter als der Status quo.

+16

Ernsthaft? Byte-Streams werden "fast nie" verwendet? Ich frage mich, auf welchem ​​Planeten dieser Typ lebt, denn in der realen Welt sind Byteströme allgegenwärtig. – augurar

26

Die meisten bytebezogenen Operationen werden automatisch zu int hochgestuft. Zum Beispiel wollen wir die einfache Methode betrachten, die eine byte Konstante zu jedem Element der byte[] Array zurückkehr neue (potentieller Kandidat für ByteStream) byte[] Array ergänzt:

public static byte[] add(byte[] arr, byte addend) { 
    byte[] result = new byte[arr.length]; 
    int i=0; 
    for(byte b : arr) { 
     result[i++] = (byte) (b+addend); 
    } 
    return result; 
} 

See, obwohl wir eine Addition von zwei byte Variablen durchführen, Sie werden auf int erweitert und Sie müssen das Ergebnis zurück auf byte werfen. In Java-Bytecode werden die meisten byte-bezogenen Operationen (außer Array laden/speichern und in Byte umwandeln) mit 32-Bit-Integer-Anweisungen (iadd, , if_icmple usw.) ausgedrückt. Somit ist es praktisch, Bytes mit IntStream als Ints zu verarbeiten. Wir müssen nur zwei zusätzliche Operationen:

  • Einen IntStream von byte[] Array (Erweiterung Bytes Ints)
  • Collect einen IntStream zu byte[] Array (mit (byte) Guss)

Die erste ist wirklich einfach und kann wie folgt implementiert werden:

public static IntStream intStream(byte[] array) { 
    return IntStream.range(0, array.length).map(idx -> array[idx]); 
} 

S o Sie können Ihrem Projekt eine solche statische Methode hinzufügen und glücklich sein.

Sammeln der Strom in byte[] Array ist schwieriger.Standard JDK-Klassen die einfachste Lösung zu verwenden ist ByteArrayOutputStream:

public static byte[] toByteArray(IntStream stream) { 
    return stream.collect(ByteArrayOutputStream::new, (baos, i) -> baos.write((byte) i), 
      (baos1, baos2) -> baos1.write(baos2.toByteArray(), 0, baos2.size())) 
      .toByteArray(); 
} 

aber es unnötigen Aufwand aufgrund Synchronisation hat. Es wäre auch schön, die Ströme bekannter Länge speziell zu verarbeiten, um die Zuweisungen und das Kopieren zu reduzieren. Trotzdem jetzt können Sie die Stream-API für byte[] Arrays verwenden:

public static byte[] addStream(byte[] arr, byte addend) { 
    return toByteArray(intStream(arr).map(b -> b+addend)); 
} 

Meine StreamEx Bibliothek beide dieser Operationen in der IntStreamEx Klasse hat die Standard IntStream verbessert, so dass Sie es wie folgt verwenden können:

public static byte[] addStreamEx(byte[] arr, byte addend) { 
    return IntStreamEx.of(arr).map(b -> b+addend).toByteArray(); 
} 

Intern toByteArray() Methode verwendet einfach resizable byte buffer und specially handles der Fall, wenn der Strom sequenziell und Zielgröße im Voraus bekannt ist.

+0

'baos1.write (baos2.toByteArray(), 0, baos2.size())' ist eine unnötig komplizierte Fusion. Zuerst gibt 'toByteArray()' immer ein Array mit der passenden Größe zurück, so dass ', 0, baos2.size()' nicht benötigt wird. Der Grund dafür, dass das Array immer die richtige Größe hat, ist, dass es immer ein neu zugewiesenes Array zurückgibt. Wenn Sie diesen Overhead vermeiden möchten, sollten Sie stattdessen 'baos2.writeTo (baos1)' 'verwenden, das ist kürzer * und * effizienter. – Holger

+0

Übrigens ist die Umwandlung von "int" nach "byte" unnötig, wenn ein einzelnes "Byte" in einen "OutputStream" geschrieben wird, daher ist "ByteArrayOutputStream :: write" als Akkumulatorfunktion ausreichend. – Holger

+0

@Holger, sowohl 'writeTo' als auch' write (byte []) 'deklarierten das Werfen einer' IOException', so dass Sie einen expliziten try-catch benötigen würden. Ich habe gerade die kürzeste Version gewählt ('write (byte [], int, int)' wirft nicht - verrückt, ich weiß). 'writeTo' wäre in der Tat effizienter. Was die explizite Besetzung angeht, erinnere ich mich nicht. Wahrscheinlich habe ich entschieden, dass eine solche Version klarer wäre. –