1. Innovazioni in Java 8: programmazione funzionale

Con il rilascio di Java 8, il linguaggio ha ottenuto un potente supporto per la programmazione funzionale . Si potrebbe anche dire che ha ottenuto il tanto atteso supporto per la programmazione funzionale. La codifica è diventata più veloce, sebbene il codice fosse più difficile da leggere 🙂

Prima di apprendere la programmazione funzionale in Java, ti consigliamo di comprendere bene tre cose:

  1. OOP, ereditarietà e interfacce ( livelli 1-2 nella ricerca Java Core ).
  2. Implementazioni di metodi predefiniti in un'interfaccia .
  3. Classi interne e anonime .

La buona notizia è che non è necessario conoscere tutto questo per utilizzare molte delle funzionalità della programmazione funzionale in Java. La cattiva notizia è che sarà difficile capire esattamente come tutto è organizzato e come tutto funziona senza conoscere le classi interne anonime.

Nelle prossime lezioni, ci concentreremo su quanto sia facile e semplice utilizzare le funzionalità di programmazione funzionale di Java, senza una profonda comprensione di come funziona.

Ci vogliono mesi per comprendere tutte le sfumature della programmazione funzionale in Java. Puoi imparare a leggere tale codice in poche ore. Quindi suggeriamo di iniziare in piccolo. Anche se è con flussi I/O.


2. Flussi di I/O: flussi di pipeline

Ricordi che una volta hai imparato a conoscere i flussi di I/O: InputStream, OutputStream, Reader, Writerecc.?

C'erano classi di flusso che leggevano i dati da origini dati , come FileInputSteam, e c'erano flussi di dati intermedi che leggevano dati da altri flussi, come InputStreamReadere BufferedReader.

Questi flussi potrebbero essere organizzati in pipeline di elaborazione dati. Ad esempio, in questo modo:

FileInputStream input = new FileInputStream("c:\\readme.txt");
InputStreamReader reader = new InputStreamReader(input);
BufferedReader buff = new BufferedReader(reader);

String text = buff.readLine();

È importante notare che nelle prime righe di codice stiamo solo costruendo una catena di Streamoggetti. I dati non sono ancora passati attraverso la pipeline.

Ma non appena chiamiamo il buff.readLine()metodo, accadrà quanto segue:

  1. L' BufferedReaderoggetto chiama il metodo read()sull'oggettoInputStreamReader
  2. L' InputStreamReaderoggetto chiama il metodo read()sull'oggettoFileInputStream
  3. L' FileInputStreamoggetto inizia a leggere i dati dal file

In altre parole, non c'è movimento di dati lungo la pipeline del flusso fino a quando non iniziamo a chiamare metodi come read()o readLine(). La semplice costruzione della pipeline del flusso non fa passare i dati attraverso di essa. I flussi stessi non memorizzano i dati. Leggono solo dagli altri.

Collezioni e flussi

A partire da Java 8, è diventato possibile ottenere uno stream per leggere i dati dalle raccolte (e non solo da esse). Ma questa non è la cosa più interessante. In realtà è diventato possibile costruire facilmente e semplicemente complesse catene di flussi di dati. E così facendo, il codice che prima richiedeva 5-10 righe ora poteva essere scritto in 1-2 righe.

Esempio di ricerca della stringa più lunga in un elenco di stringhe:

Trovare la corda più lunga
ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");
String max = list.stream().max((s1, s2)-> s1.length()-s2.length()).get();
ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");
Stream<String> stream = list.stream();
Optional<String> optional = stream.max((s1, s2)-> s1.length()-s2.length());
String max = optional.get();

3. Streaminterfaccia

Il supporto esteso di Java 8 per i flussi viene implementato utilizzando l' Stream<T>interfaccia, dove Tè un parametro di tipo che indica il tipo di dati passati nel flusso. In altre parole, un flusso è completamente indipendente dal tipo di dati che trasmette.

Per ottenere un oggetto stream da una collection , basta chiamare il suo stream()metodo. Il codice è più o meno così:

Stream<Type> name = collection.stream();
Ottenere un flusso da una raccolta

In questo caso, la raccolta sarà considerata l'origine dati del flusso e l' Stream<Type>oggetto sarà uno strumento per ottenere dati dalla raccolta sotto forma di flusso di dati.

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");
Stream<String> stream = list.stream();

A proposito, puoi ottenere un flusso non solo dalle raccolte, ma anche dagli array . Per fare ciò, è necessario utilizzare il metodo. Per esempio:Arrays.stream()

Stream<Type> name = Arrays.stream(array);
Ottenere un flusso da un array

In questo caso, l' array verrà considerato l'origine dati per il flusso denominato name.

Integer[] array = {1, 2, 3};
Stream<Integer> stream = Arrays.stream(array);

Nessun dato viene spostato quando Stream<Type>viene creato l'oggetto. Abbiamo semplicemente ottenuto un oggetto flusso per iniziare a costruire una pipeline di flusso.