-
Lo stile funzionale introdotto in Java 8 ci aiuta a ridurre il divario tra logica aziendale e codice. Ci permette di raccontare la storia in un flusso naturale a un livello superiore. Invece di dire come vuoi farlo, puoi dire cosa vuoi fare.
-
Il codice diventa più pulito e conciso.
-
Le funzioni di ordine elevato ci permettono di:
- Invia funzioni ad altre funzioni
- Creare funzioni all'interno di altre funzioni
- Restituisce funzioni da altre funzioni
Questa è una grande vittoria per Java, poiché per farlo dobbiamo inviare, creare e restituire oggetti. Saremo in grado di scrivere codice più affidabile, mirato e più facile da riutilizzare.
-
Grazie ai lambda possiamo fare calcoli pigri. Quando un'espressione lambda viene inviata come argomento del metodo, il compilatore la valuterà quando verrà chiamata nel metodo. Questo è diverso dagli argomenti del metodo normale, che vengono valutati immediatamente.
-
I lambda rendono divertente la scrittura dei test unitari. Ci consentono di creare test leggeri, puliti, di piccole dimensioni e veloci da scrivere. Possiamo sradicare il codice in prova utilizzando lambda. Questo ci consente di testare come tutti i tipi di scenari influenzeranno il codice.
-
Nuovi modelli da imparare.
-
E altro ancora!
break
, cambiano radicalmente il comportamento del ciclo, costringendoci a capire non solo cosa il codice sta cercando di ottenere, continue
ma return
anche come funziona il ciclo. Ora daremo un'occhiata a come possiamo trasformare i loop in codice più conciso e leggibile.
Che la codifica abbia inizio!
Lavoreremo con articoli. Un articolo ha un titolo, un autore e diversi tag.private class Article {
private final String title;
private final String author;
private final List<String> tags;
private Article(String title, String author, List<String> tags) {
this.title = title;
this.author = author;
this.tags = tags;
}
public String getTitle() {
return title;
}
public String getAuthor() {
return author;
}
public List<String> getTags() {
return tags;
}
}
Ogni esempio conterrà una soluzione tradizionale che utilizza i loop e una soluzione che utilizza le nuove funzionalità di Java 8. Nel primo esempio, vogliamo trovare il primo articolo della raccolta con il tag “Java”. Diamo un'occhiata a una soluzione utilizzando un ciclo.
public Article getFirstJavaArticle() {
for (Article article : articles) {
if (article.getTags().contains("Java")) {
return article;
}
}
return null;
}
Ora risolviamo il problema utilizzando le operazioni dell'API Stream.
public Optional<Article> getFirstJavaArticle() {
return articles.stream()
.filter(article -> article.getTags().contains("Java"))
.findFirst();
}
Abbastanza bello, non è vero? Utilizziamo innanzitutto l'operazione filter
per trovare tutti gli articoli con il tag “Java”, quindi utilizziamo findFirst()
per ottenere la prima occorrenza. Poiché i flussi sono lenti e il filtro restituisce un flusso, questo approccio elaborerà solo gli elementi finché non troverà la prima corrispondenza. Ora inseriamo tutti gli articoli contrassegnati con "Java" anziché solo il primo. Innanzitutto la soluzione utilizzando i loop.
public List<Article> getAllJavaArticles() {
List<Article> result = new ArrayList<>();
for (Article article : articles) {
if (article.getTags().contains("Java")) {
result.add(article);
}
}
return result;
}
Soluzione che utilizza operazioni di flusso.
public List<Article> getAllJavaArticles() {
return articles.stream()
.filter(article -> article.getTags().contains("Java"))
.collect(Collectors.toList());
}
In questo esempio abbiamo utilizzato un'operazione collect
per abbreviare il flusso risultante, anziché dichiarare una raccolta e aggiungere esplicitamente le voci corrispondenti. Fin qui tutto bene. È tempo di esempi che faranno davvero brillare l'API Stream. Raggruppiamo tutti gli articoli per autore. Come al solito, iniziamo risolvendolo utilizzando i loop:
public Map<String, List<Article>> groupByAuthor() {
Map<String, List<Article>> result = new HashMap<>();
for (Article article : articles) {
if (result.containsKey(article.getAuthor())) {
result.get(article.getAuthor()).add(article);
} else {
ArrayList<Article> articles = new ArrayList<>();
articles.add(article);
result.put(article.getAuthor(), articles);
}
}
return result;
}
Possiamo trovare una soluzione pulita a questo problema utilizzando le operazioni di flusso?
public Map<String, List<Article>> groupByAuthor() {
return articles.stream()
.collect(Collectors.groupingBy(Article::getAuthor));
}
Sorprendente! Utilizzando un'operazione groupingBy
e un riferimento al metodo getAuthor()
, otteniamo un codice pulito e leggibile. Ora troviamo il resto dei tag utilizzati nella raccolta. Iniziamo con un esempio di ciclo:
public Set<String> getDistinctTags() {
Set<String> result = new HashSet<>();
for (Article article : articles) {
result.addAll(article.getTags());
}
return result;
}
Ok, diamo un'occhiata a come possiamo risolvere questo problema utilizzando le operazioni di flusso:
public Set<String> getDistinctTags() {
return articles.stream()
.flatMap(article -> article.getTags().stream())
.collect(Collectors.toSet());
}
Freddo! flatmap
ci aiuta ad appiattire l'elenco di tag in un unico flusso di risultati, che poi utilizziamo collect
per creare il set restituito.
GO TO FULL VERSION