Questo tutorial di Java 8 elenca importanti funzionalità introdotti in questa versione. Tutte le funzionalità hanno collegamenti a tutorial dettagliati come espressioni lambda, flussi Java, interfacce funzionali e modifiche dell'API data/ora.

1. Expressioni Lambda 

Le espressioni lambda non sono sconosciute a molti di noi che hanno lavorato su altri linguaggi di programmazione popolari come Scala. Nel linguaggio di programmazione Java, un'espressione (o funzione) Lambda è solo una funzione anonima, ovvero una funzione senza nome e senza essere associata a un identificatore. Sono scritti esattamente nel luogo in cui è necessario, in genere come parametro per un'altra funzione.

La sintassi di base di un'espressione lambda è:

either
(parameters) -> expression
or
(parameters) -> { statements; }
or
() -> expression

Un tipico esempio di espressione lambda sarà così:

(x, y) -> x + y  // Questa funzione accetta due parametri e restituisce la loro somma.

Si noti che in base al tipo di xey, il metodo può essere utilizzato in più punti. I parametri possono corrispondere a int, o Integer o semplicemente String. In base al contesto, aggiungerà due numeri interi o concatenerà due stringhe.

Regole per scrivere espressioni lambda:

  1. Un'espressione lambda può avere zero, uno o più parametri.
  2. Il tipo di parametri può essere esplicitamente dichiarato o può essere dedotto dal contesto.
  3. Più parametri sono racchiusi tra parentesi obbligatorie e separati da virgole. Le parentesi vuote vengono utilizzate per rappresentare un insieme vuoto di parametri.
  4. Quando esiste un singolo parametro, se il suo tipo viene dedotto, non è obbligatorio utilizzare le parentesi. per esempio. a -> restituisce a * a.
  5. Il corpo delle espressioni lambda può contenere zero, una o più istruzioni.
  6. Se il corpo dell'espressione lambda ha parentesi graffe a singola istruzione non obbligatorie e il tipo restituito della funzione anonima è uguale a quello dell'espressione corporea. Quando nel corpo è presente più di un'istruzione, queste devono essere racchiuse tra parentesi graffe.

2. Interfacce Funzionali

Le interfacce funzionali sono anche chiamate interfacce Single Abstract Method (SAM Interfaces). Come suggerisce il nome, consentono esattamente un metodo astratto al loro interno. Java 8 introduce un'annotazione, ad esempio @FunctionalInterface, che può essere utilizzata per errori a livello di compilatore quando l'interfaccia annotata viola i contratti di Functional Interface.

Un tipico esempio di interfaccia funzionale:

@FunctionalInterface
public interface MyFirstFunctionalInterface {
    public void firstWork();
}
Si noti che un'interfaccia funzionale è valida anche se l'annotazione @FunctionalInterface verrebbe omessa. Serve solo per informare il compilatore di imporre un singolo metodo astratto all'interno dell'interfaccia.
Inoltre, poiché i metodi predefiniti non sono astratti, sei libero di aggiungere metodi predefiniti all'interfaccia funzionale quanti ne desideri.

Un altro punto importante da ricordare è che se un'interfaccia dichiara un metodo astratto che sovrascrive uno dei metodi pubblici di java.lang.Object, anche questo non conta per il conteggio dei metodi astratti dell'interfaccia poiché qualsiasi implementazione dell'interfaccia avrà un'implementazione da java .lang.Object o altrove. ad esempio, di seguito è un'interfaccia funzionale perfettamente valida.
@FunctionalInterface
public interface MyFirstFunctionalInterface
{
    public void firstWork();
 
    @Override
    public String toString();                //Overridden from Object class
 
    @Override
    public boolean equals(Object obj);        //Overridden from Object class
}

3. Metodi Predefiniti

Java 8 consente di aggiungere metodi non astratti nelle interfacce. Questi metodi devono essere dichiarati metodi predefiniti. I metodi predefiniti sono stati introdotti in Java 8 per abilitare la funzionalità dell'espressione lambda.

I metodi predefiniti consentono di aggiungere nuove funzionalità alle interfacce delle librerie e garantire la compatibilità binaria con il codice scritto per le versioni precedenti di tali interfacce.

Comprendiamo con un esempio:

public interface Moveable {
    default void move(){
        System.out.println("I am moving");
    }
}

L'interfaccia mobile definisce un metodo move () e ha fornito anche un'implementazione predefinita. Se una classe implementa questa interfaccia, non è necessario implementare la propria versione del metodo move (). Può chiamare direttamente instance.move (). per esempio.

public class Animal implements Moveable{
    public static void main(String[] args){
        Animal tiger = new Animal();
        tiger.move();
    }
}
  
Output: I am moving

Se la classe desidera personalizzare volutamente il comportamento del metodo move (), può fornire la propria implementazione personalizzata e sovrascrivere il metodo.

4. Streams

Un'altra importante modifica ha introdotto l'API Java 8 Streams, che fornisce un meccanismo per l'elaborazione di una serie di dati in vari modi che può includere il filtro, la trasformazione o qualsiasi altro modo che possa essere utile a un'applicazione.

L'API di stream in Java 8 supporta un diverso tipo di iterazione in cui si definisce semplicemente l'insieme di elementi da elaborare, le operazioni da eseguire su ciascun elemento e dove deve essere archiviato l'output di tali operazioni.

Un esempio di API di flusso. In questo esempio, gli elementi sono una raccolta di valori String e si desidera rimuovere le voci che iniziano con del testo prefisso.

List<String> items;
String prefix;
List<String> filteredList = items.stream().filter(e -> (!e.startsWith(prefix))).collect(Collectors.toList())

Qui items.stream () indica che desideriamo che i dati nella raccolta degli articoli vengano elaborati utilizzando l'API Streams.

5. Date/Time API Changes

Le nuove API / classi di data e ora (JSR-310), chiamate anche ThreeTen, che hanno semplicemente cambiato il modo in cui hai gestito le date nelle applicazioni Java.

Date: La classe di data è persino diventata obsoleta. Le nuove classi che intendono sostituire la classe Date sono LocalDate, LocalTime e LocalDateTime.

  1. La classe LocalDate rappresenta una data. Non è presente alcuna rappresentazione di un fuso orario o di un fuso orario.
  2. La classe LocalTime rappresenta un'ora. Non c'è rappresentazione di una data o fuso orario.
  3. La classe LocalDateTime rappresenta una data-ora. Non c'è rappresentazione di un fuso 
Se si desidera utilizzare la funzionalità di data con le informazioni sulla zona, Lambda fornisce 3 classi aggiuntive simili a una sopra, ad esempio OffsetDate, OffsetTime e OffsetDateTime. La differenza di fuso orario può essere rappresentata nei formati “+05: 30” o “Europa / Parigi”. Questo viene fatto utilizzando un'altra classe, ad esempio ZoneId.

LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.of(12, 20);
LocalDateTime localDateTime = LocalDateTime.now();
OffsetDateTime offsetDateTime = OffsetDateTime.now();
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Paris"));
​

6. Data/Ora e durata

Per rappresentare la formica data / ora specifica in qualsiasi momento, la classe che deve essere utilizzata è Istantanea. La classe Instant rappresenta un istante nel tempo con una precisione di nanosecondi. Le operazioni su un Instant includono il confronto con un altro Instant e l'aggiunta o la sottrazione di una durata.

Instant instant = Instant.now();
Instant instant1 = instant.plus(Duration.ofMillis(5000));
Instant instant2 = instant.minus(Duration.ofMillis(5000));
Instant instant3 = instant.minusSeconds(10);
La lezione di durata è un concetto completamente nuovo introdotto per la prima volta in linguaggio java. Rappresenta la differenza di tempo tra due timestamp.
Duration duration = Duration.ofMillis(5000);
duration = Duration.ofSeconds(60);
duration = Duration.ofMinutes(10);
La durata si occupa di una piccola unità di tempo come millisecondi, secondi, minuti e ora. Sono più adatti per interagire con il codice dell'applicazione. Per interagire con l'essere umano, devi ottenere durate maggiori che vengono presentate con la classe Period.
Period period = Period.ofDays(6);
period = Period.ofMonths(6);
period = Period.between(LocalDate.now(), LocalDate.now().plusDays(60));