web-dev-qa-db-fra.com

Dans Java 8, existe-t-il une classe ByteStream?

Java 8 fournit Stream<T> spécialisations pour double, int et long: DoubleStream, IntStream et LongStream respectivement. Cependant, je n'ai pas pu trouver d'équivalent pour byte dans la documentation .

Java 8 fournit-il une classe ByteStream?

35
sdgfsdh

Non, ça n'existe pas. En fait, il n'a pas été explicitement implémenté afin de ne pas encombrer l'API Stream avec des tonnes de classes pour chaque type primitif.

Citant n mail de Brian Goetz dans la liste de diffusion OpenJDK:

Réponse courte: non.

Cela ne vaut pas 100K + d'empreinte JDK chacun pour ces formulaires qui ne sont presque jamais utilisés. Et si nous les ajoutions, quelqu'un demanderait court, flottant ou booléen.

Autrement dit, si les gens insistaient pour que nous ayons toutes les spécialisations primitives, nous n'aurions pas de spécialisations primitives. Ce qui serait pire que le statu quo.

32
Tunaki

La plupart des opérations liées aux octets sont automatiquement promues en int. Par exemple, considérons la méthode simple qui ajoute une constante byte à chaque élément du tableau byte[] Renvoyant un nouveau tableau byte[] (Candidat potentiel pour 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;
}

Voir, même si nous effectuons l'ajout de deux variables byte, elles sont élargies à int et vous devez convertir le résultat en byte. Dans Java bytecode la plupart des opérations liées à byte (sauf le chargement/stockage de tableau et la conversion en octets) sont exprimées avec des instructions entières de 32 bits (iadd, ixor, if_icmple et ainsi de suite). Ainsi, il est pratiquement possible de traiter les octets en tant qu'entres avec IntStream. Nous avons juste besoin de deux opérations supplémentaires:

  • Créer un IntStream à partir du tableau byte[] (Élargissement des octets en pouces)
  • Collectez un tableau IntStream vers byte[] (En utilisant (byte) Cast)

Le premier est vraiment simple et peut être implémenté comme ceci:

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

Vous pouvez donc ajouter une telle méthode statique à votre projet et être heureux.

La collecte du flux dans le tableau byte[] Est plus délicate. En utilisant des classes JDK standard, la solution la plus simple est 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();
}

Cependant, il a des frais généraux inutiles en raison de la synchronisation. Il serait également agréable de traiter spécialement les flux de longueur connue pour réduire les allocations et la copie. Néanmoins, vous pouvez maintenant utiliser l'API Stream pour les tableaux byte[]:

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

Ma bibliothèque StreamEx a ces deux opérations dans la classe IntStreamEx qui améliore la norme IntStream, vous pouvez donc l'utiliser comme ceci:

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

En interne, la méthode toByteArray() utilise un redimensionnement simple tampon d'octets et gère spécialement le cas où le flux est séquentiel et la taille cible connue à l'avance.

36
Tagir Valeev