2015-09-08 66 views
19

Java 8 fornisce Stream<T> specializzazioni per double, int e long: DoubleStream, IntStream e LongStream rispettivamente. Tuttavia, non ho trovato un equivalente per byte in the documentation.In Java 8, esiste una classe ByteStream?

Java 8 fornisce una classe ByteStream?

+2

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

risposta

23

No, non esiste. In realtà, non è stato esplicitamente implementato in modo da non ingombrare l'API Stream con tonnellate di classi per ogni tipo primitivo.

Citando a mail di Brian Goetz nella mailing list OpenJDK:  

Risposta breve: no.

Non vale un altro 100K + di ingombro JDK ciascuno per queste forme che vengono utilizzate quasi mai. E se li avessimo aggiunti, qualcuno avrebbe richiesto short, float o booleano.

In altre parole, se le persone insistessero sul fatto che avevamo tutte le primitive specializzazioni , non avremmo specializzazioni primitive. Quale sarebbe peggio dello status quo.

+16

Seriamente? I flussi di byte vengono utilizzati "quasi mai"? Mi chiedo su quale pianeta stia vivendo quel ragazzo, perché nel mondo reale i flussi di byte sono onnipresenti. – augurar

26

La maggior parte delle operazioni relative ai byte viene automaticamente promossa a int. Per esempio, consideriamo il metodo semplice che aggiunge una costante byte ad ogni elemento della byte[] matrice rinvio nuovo byte[] array (potenziale candidato ByteStream):

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, anche se eseguiamo un'aggiunta di due byte variabili, sono ampliati a int e devi restituire il risultato a byte. Nel bytecode Java la maggior parte delle operazioni correlate a byte (ad eccezione di caricamento/archiviazione dell'array e cast in byte) sono espresse con istruzioni integer a 32 bit (iadd, ixor, if_icmple e così via). Pertanto, in pratica, è possibile elaborare byte come intersezioni con IntStream. Dobbiamo solo due operazioni aggiuntive:

  • creare un IntStream da byte[] matrice (allargamento byte interi)
  • Raccogliere un array IntStream a byte[] (usando (byte) getto)

Il primo è davvero facile e può essere implementato in questo modo:

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

S o puoi aggiungere questo metodo statico al tuo progetto ed essere felice.

La raccolta dello stream nell'array byte[] è più complessa.Utilizzo di classi JDK standard, la soluzione più semplice è 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(); 
} 

Tuttavia ha inutile sovraccarico a causa di sincronizzazione. Inoltre sarebbe bello elaborare in modo speciale i flussi di lunghezza nota per ridurre le allocazioni e la copia. Tuttavia ora è possibile utilizzare l'API di flusso per byte[] array:

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

Biblioteca StreamEx ha entrambe queste operazioni nella classe IntStreamEx che migliora standard di IntStream, in modo da poter usare in questo modo:

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

Internamente il metodo toByteArray() utilizza il semplice ridimensionabile byte buffer e specially handles il caso in cui lo streaming è sequenziale e la dimensione della destinazione è nota in anticipo.

+0

'baos1.write (baos2.toByteArray(), 0, baos2.size())' è una fusione inutilmente complicata. Innanzitutto, 'toByteArray()' restituisce sempre un array di dimensioni appropriate, quindi ', 0, baos2.size()' non è necessario. Il motivo, l'array è sempre dimensionato in modo appropriato, è che restituisce sempre un array appena assegnato. Se vuoi evitare questo overhead, considera l'utilizzo di 'baos2.writeTo (baos1)', invece, è più breve * e * più efficiente. – Holger

+0

A proposito, il cast da 'int' a' byte' non è necessario quando si scrive un singolo 'byte' in un' OutputStream', quindi 'ByteArrayOutputStream :: write' è sufficiente come funzione di accumulatore. – Holger

+0

@Holger, sia 'writeTo' che' write (byte []) 'hanno dichiarato di lanciare un' IOException', quindi è necessario un try-catch esplicito. Ho appena selezionato la versione più breve ('write (byte [], int, int)' non gira - pazzo, lo so). 'writeTo' sarebbe effettivamente più efficiente. Per quanto riguarda il cast esplicito, non ricordo. Probabilmente ho deciso che tale versione sarebbe stata più chiara. –