Esercitazione su Java 8
"Java è ancora vivo e le persone stanno iniziando a capirlo."
Benvenuti nella mia introduzione a Java 8. Questo articolo vi guiderà passo dopo passo attraverso tutte le nuove funzionalità da Java 7 a Java 8. Con esempi di codice semplici e rapidi, possiamo imparare come utilizzare le interfacce predefinite, i riferimenti ai
metodi e Annotazioni ripetibili . Alla fine dell'articolo faremo conoscenza con l'API Stream.
Nessuna chiacchiera inutile: solo codice e commenti! Inoltrare!
Metodi predefiniti per le interfacce
Java 8 ci consente di aggiungere metodi non astratti (che vengono implementati) alle interfacce aggiungendo l'estensione
default
. Questa funzionalità è nota anche come
metodi di estensione . Di seguito è riportato il primo esempio:
interface Formula {
double calculate(int a);
default double sqrt(int a) {
return Math.sqrt(a);
}
}
Oltre al metodo astratto
calculate
, l'interfaccia
Formula
definisce anche un metodo predefinito
sqrt
. Le classi che implementano questa interfaccia devono solo implementare
calculate
. Il metodo predefinito
sqrt
può essere utilizzato immediatamente.
Formula formula = new Formula() {
@Override
public double calculate(int a) {
return sqrt(a * 100);
}
};
formula.calculate(100);
formula.sqrt(16);
L'interfaccia
Formula
è implementata come classe anonima. Il codice è ridondante: 6 righe per l'implementazione
sqrt(a * 100)
. Come vedremo nella sezione successiva, esiste un modo più carino per implementare un singolo metodo in Java 8.
Espressioni lambda
Cominciamo con un semplice esempio di ordinamento di un elenco di stringhe nelle versioni precedenti di Java:
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
Il metodo statico
Collections.sort
accetta una lista e un comparatore nell'ordine in cui la lista deve essere ordinata. Puoi sempre creare una classe comparatrice anonima e trasmetterla. Invece di creare una classe anonima, in Java 8 puoi creare una notazione più breve, un'espressione lambda.
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
Come puoi vedere il codice è molto più breve e più facile da leggere. Ma questo può essere reso ancora più breve:
Collections.sort(names, (String a, String b) -> b.compareTo(a));
Per un corpo con una riga, puoi saltare
{}
la parola
return
. Ma puoi renderlo ancora più breve:
Collections.sort(names, (a, b) -> b.compareTo(a));
Il compilatore Java conosce i tipi di argomento, quindi puoi anche saltarli. Esaminiamo più a fondo le espressioni lambda e comprendiamo come possono essere utilizzate.
Interfacce funzionali
Come si inseriscono le espressioni lambda nel sistema di tipi Java? Ogni lambda corrisponde a un tipo descritto nell'interfaccia. Pertanto, un'interfaccia funzionale dovrebbe contenere un solo metodo astratto. Ogni espressione lambda di questo tipo corrisponderà a questo metodo astratto. Poiché i metodi predefiniti non sono astratti, sei libero di creare metodi predefiniti nelle interfacce funzionali secondo necessità. Possiamo anche utilizzare interfacce arbitrarie come espressioni lambda se in questa interfaccia è presente un solo metodo astratto. Per soddisfare questi requisiti, è necessario aggiungere
@FucntionalInterface
un'annotazione. Il compilatore lo sa e lancerà un'eccezione se desideri fornire più di un metodo astratto. Esempio:
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
}
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted);
Tieni presente che il codice verrà compilato anche se
@FunctionalInterface
l'annotazione viene omessa.
Riferimenti al metodo e al costruttore
L'esempio sopra può anche essere reso ancora più piccolo utilizzando i riferimenti al metodo:
Converter<String, Integer> converter = Integer::valueOf;
Integer converted = converter.convert("123");
System.out.println(converted);
Java 8 consente di passare riferimenti a un metodo o costruttore aggiungendo
::
. L'esempio sopra mostra come possiamo fare riferimento a un metodo statico, sebbene possiamo anche fare riferimento a metodi non statici:
class Something {
String startsWith(String s) {
return String.valueOf(s.charAt(0));
}
}
Something something = new Something();
Converter<String, String> converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted);
Vediamo come
::
funziona con i costruttori. Per iniziare, definiremo una classe di esempio con diversi costruttori:
class Person {
String firstName;
String lastName;
Person() {}
Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
Successivamente, definiremo un'interfaccia per la creazione di nuovi oggetti:
interface PersonFactory<P extends Person> {
P create(String firstName, String lastName);
}
Invece di implementare una factory di creazione, collegheremo il tutto con
::
l'aiuto del costruttore:
PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("Peter", "Parker");
Abbiamo creato un collegamento al costruttore tramite
Person::new
. Il compilatore Java selezionerà automaticamente il costruttore corretto che corrisponde alla firma del metodo
PersonFactory.create
. ... Continua. Sfortunatamente, non ho trovato il modo di salvare una bozza dell'articolo, e questo è davvero strano, e il tempo per la traduzione è scaduto, quindi lo finirò più tardi. Per tutti coloro che conoscono e capiscono l'inglese -
Articolo originale . Se avete suggerimenti per correggere la traduzione, scrivete con qualsiasi modo a vostra disposizione.
Il mio account Github
GO TO FULL VERSION