2015-09-20 15 views
8

È possibile creare stream da com.fasterxml.jackson.databind.node.ArrayNode?
ho provato:Creazione di Java 8 Stream da ArrayNode

ArrayNode files = (ArrayNode) json.get("files"); 
Stream<JsonNode> stream = Stream.of(files); 

ma sarà effettivamente dare flusso di un elemento, l'oggetto ArrayNode iniziale.
Il risultato corretto dovrebbe essere Stream<JsonNode>, posso raggiungerlo?

+1

L'intero array verrà caricato in memoria? Credo che la risposta sia sì". Allora, qual è il punto di avere un flusso qui? –

+0

@AndreyKarayvansky non si tratta di prestazioni ma dell'abilità di utilizzare i metodi 'Java 8 Stream API' per elaborare la raccolta' ArrayNode' in un "modo funzionale" (usando metodi come 'map',' filter', 'collect' ...) . – icl7126

risposta

4

ArrayNode # elementi restituisce un iteratore su di esso è elementi è possibile utilizzare che per creare un flusso (sfruttando StreamSupport). StreamSupport richiede uno Spliterator e per creare uno Spliterator da un Iterator puoi usare la classe Spliterators.

ArrayNode files = (ArrayNode) json.get("files"); 
    Stream<JsonNode> elementStream = StreamSupport.stream(Spliterators 
        .spliteratorUnknownSize(files.elements(), 
         Spliterator.ORDERED),false); 

cyclops-streams ha una classe StreamUtils ha un metodo statico che rende questo un po 'più pulito (io sono l'autore).

ArrayNode files = (ArrayNode) json.get("files"); 
Stream<JsonNode> elementStream = StreamUtils.stream(files.elements()); 

Tenendo conto @JB risposta di Nizet che ArrayNode è un iterabile con StreamUtils è possibile passare in ArrayNode e ottenere il flusso di nuovo direttamente.

Stream<JsonNode> elementStream = StreamUtils.stream((ArrayNode) json.get("files")); 
7

Una classe ArrayNode fornisce accesso casuale: è possibile ottenere size() e un elemento in base all'indice (utilizzando get(index)). Questo è tutto ciò che serve per creare un buon flusso:

Stream<JsonNode> nodes = IntStream.range(0, files.size()).mapToObj(files::get); 

Si noti che questa soluzione è meglio che usare spliterator di default (come suggerito da altri answerers) in quanto si può dividere bene e riporta il formato corretto. Anche se non ti interessa l'elaborazione parallela, alcune operazioni come toArray() funzioneranno in modo più efficace poiché conoscere in anticipo le dimensioni aiuterà ad allocare un array di dimensioni appropriate.

+0

Sono d'accordo con tutto ciò che hai detto e questa è in molti modi una soluzione migliore. Ma mi aspetterei di vedere tale soluzione direttamente nella classe 'ArrayNode' o come metodo' Utils'. Gli stream dovrebbero rendere il codice più facile da leggere e capire. L'utilizzo di questa soluzione per una semplice operazione filter-map-collect aumenterebbe leggermente la complessità del codice. Ad ogni modo, pensando molto bene, hai il mio +1. – icl7126

+0

@klerik, Non è così semplice fornire i metodi API del flusso mantenendo la compatibilità pre-Java-8. –