Perché preferiresti API Java 8 Stream invece di query hibernate/sql dirette quando lavori con il DB




java-8 java-stream (4)

Recentemente vedo un sacco di codice in pochi progetti che usano lo stream per filtrare oggetti, come:

library.stream()
          .map(book -> book.getAuthor())
          .filter(author -> author.getAge() >= 50)
          .map(Author::getSurname)
          .map(String::toUpperCase)
          .distinct()
          .limit(15)
          .collect(toList()));

C'è qualche vantaggio nell'usarlo invece della query HQL / SQL diretta al database che restituisce già i risultati filtrati.

Il secondo approccio non è molto più veloce?


A meno che non siano misurati e provati per uno scenario specifico, potrebbero essere buoni o ugualmente cattivi. Il motivo per cui di solito vuoi fare questo tipo di query al database è perché (tra le altre cose):

DB può gestire dati molto più grandi del tuo processo java

Le query in un database possono essere indicizzate (rendendole molto più veloci)

D'altra parte, se i tuoi dati sono piccoli, l'uso di un Stream come hai fatto è efficace. Scrivere una pipeline come Stream è molto leggibile (una volta che si parla di stream abbastanza buoni).


A prima vista: i flussi possono essere fatti per correre in parallelo; semplicemente cambiando il codice per usare parallelStream() . (disclaimer: ovviamente dipende dal contesto specifico se solo cambiando il tipo di stream si otterranno risultati corretti, ma sì, può essere così facile).

Quindi: gli stream "invitano" a utilizzare espressioni lambda. E quelli a loro volta portano all'uso delle istruzioni invoke_dynamic bytecode; a volte ottenendo vantaggi in termini di prestazioni rispetto al tipo di "vecchia scuola" di scrivere tale codice. (e per chiarire l'equivoco: invoke_dynamic è una proprietà di lambda, non di stream!)

Questi sarebbero i motivi per preferire le soluzioni "stream" al giorno d'oggi (da un punto di vista generale).

Oltre a ciò: dipende davvero ... diamo un'occhiata al tuo input di esempio. Sembra che si tratti di POJO Java ordinari, che già risiedono in memoria, all'interno di una sorta di collezione. L'elaborazione diretta di tali oggetti nella memoria sarebbe sicuramente più veloce di andare in qualche database fuori processo per lavorare lì!

Ma, naturalmente: quando le chiamate di cui sopra, come book.getAuthor() farebbero un "deep dive" e parlerebbero effettivamente con un database sottostante; quindi è probabile che "fare il tutto in una singola query" ti offra prestazioni migliori.


Hibernate e altri ORM sono in genere più utili per scrivere entità piuttosto che leggere, perché consentono agli sviluppatori di scaricare l'ordine di scritture specifiche su framework che quasi mai "sbagliano".

Ora, per la lettura e il reporting, d'altra parte (e considerando che stiamo parlando di DB qui) una query SQL è probabilmente migliore perché non ci saranno framework nel mezzo, e sarete in grado di regolare le prestazioni della query in termini del database che invocherà questa query piuttosto che in termini del tuo quadro di scelta, che offre una maggiore flessibilità su come può essere fatta la messa a punto, in un certo senso.


La prima cosa è rendersi conto, che non si può dire solo da questo codice, quale affermazione viene emessa contro il database. Potrebbe benissimo, che tutto il filtraggio, la limitazione e la mappatura siano raccolti, e al momento dell'invocazione di collect tutte le informazioni siano utilizzate per costruire un'istruzione SQL corrispondente (o qualunque linguaggio di query sia usato) e inviarle al database.

Con questo in mente ci sono molte ragioni per le quali vengono utilizzate API streamlike.

  1. È alla moda Streams e lambda sono ancora piuttosto nuovi per la maggior parte degli sviluppatori di java, quindi si sentono bene quando lo usano.

  2. Se viene utilizzato qualcosa come nel primo paragrafo, in realtà crea un bel DSL per costruire le tue istruzioni di query. Scalas Slick e. LINQ .Net, dove sono i primi esempi che conosco, anche se presumo che qualcuno costruisca qualcosa del genere in LISP molto tempo prima che io nascessi.

  3. Gli stream potrebbero essere flussi reattivi e incapsulare un'API non bloccante. Mentre queste API sono davvero belle perché non ti costringono a bloccare risorse come i thread mentre stai aspettando i risultati. L'utilizzo di questi richiede tonnellate di callback o l'utilizzo di un'API basata sul flusso più gradevole per elaborare i risultati.

  4. Sono più bravi a leggere il codice imperativo. Forse l'elaborazione eseguita nello stream non può [facilmente / dall'autore] essere eseguita con SQL. Quindi le alternative non sono SQL vs Java (o che lingua mai utilizzata), ma Java imperativo o Java "funzionale". Più tardi si legge spesso più bello.

Quindi ci sono buone ragioni per usare questa API.

Detto ciò: in quasi tutti i casi è una cattiva idea quella di eseguire qualsiasi tipo di ordinamento / filtro e simili nell'applicazione, quando è possibile scaricarla nel database. L'unica eccezione a cui posso pensare attualmente è quando puoi saltare l'intero roundtrip al database, perché hai già il risultato a livello locale (ad esempio in una cache).





java-stream