Java 14 ha introdotto un nuovo modo per creare classi chiamato Records. In questo tutorial, impareremo:
- Perché abbiamo bisogno di Java Records
- Come creare Records e usarli
- Override ed estensione delle classi Records
Lettura consigliata: Java 14 Caratteristiche
Perché abbiamo bisogno di Java Records?
Uno dei comuni lamenti su Java è stata la sua verbosità. Se devi creare una semplice classe POJO, richiede il seguente codice boilerplate.
- Campi privati
- Metodi Getter e Setter
- Costruttori
- Metodi hashCode(), equals() e toString()
Questa verbosità è una delle ragioni dell’alto interesse per Kotlin e Project Lombok.
In effetti, la pura frustrazione di scrivere questi metodi generici ogni volta ha portato alla creazione di scorciatoie per generarli nelle IDE Java come Eclipse e IntelliJ IDEA.
Ecco uno screenshot che mostra l’opzione dell’IDE Eclipse per generare i metodi cerimoniali per una classe.

I Java Records sono pensati per eliminare questa verbosità fornendo una struttura compatta per creare le classi POJO.
Come creare i Java Records
I Records di Java sono una funzionalità di anteprima, sviluppata nell’ambito di JEP 359. Quindi, hai bisogno di due cose per creare i Records nei tuoi progetti Java.
- JDK 14 installato. Se stai usando un IDE, deve anche supportare Java 14. Sia Eclipse che IntelliJ forniscono già supporto per Java 14, quindi siamo a posto qui.
- Abilita la Funzionalità di Anteprima: Di default, le funzionalità di anteprima sono disabilitate. Puoi abilitarle in Eclipse dalle impostazioni del compilatore Java del progetto.

Puoi abilitare le funzionalità di anteprima di Java 14 da riga di comando utilizzando l’opzione --enable-preview -source 14
.
Supponiamo che voglia creare una classe modello Employee. Avrà un aspetto simile al codice seguente.
package com.journaldev.java14;
import java.util.Map;
public class Employee {
private int id;
private String name;
private long salary;
private Map<String, String> addresses;
public Employee(int id, String name, long salary, Map<String, String> addresses) {
super();
this.id = id;
this.name = name;
this.salary = salary;
this.addresses = addresses;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public long getSalary() {
return salary;
}
public Map<String, String> getAddresses() {
return addresses;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((addresses == null) ? 0 : addresses.hashCode());
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + (int) (salary ^ (salary >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (addresses == null) {
if (other.addresses != null)
return false;
} else if (!addresses.equals(other.addresses))
return false;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (salary != other.salary)
return false;
return true;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + ", addresses=" + addresses + "]";
}
}
Uff, sono più di 70 righe di codice generato automaticamente. Ora vediamo come creare una classe Employee Record, che fornisce essenzialmente le stesse funzionalità.
package com.journaldev.java14;
import java.util.Map;
public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {
}
Wow, questo non può diventare più breve di così. Mi stanno già piacendo le classi Record.
Ora, utilizziamo il comando javap
per capire cosa succede dietro le quinte quando un Record viene compilato.
# javac --enable-preview -source 14 EmpRecord.java
Note: EmpRecord.java uses preview language features.
Note: Recompile with -Xlint:preview for details.
# javap EmpRecord
Compiled from "EmpRecord.java"
public final class EmpRecord extends java.lang.Record {
public EmpRecord(int, java.lang.String, long, java.util.Map<java.lang.String, java.lang.String>);
public java.lang.String toString();
public final int hashCode();
public final boolean equals(java.lang.Object);
public int id();
public java.lang.String name();
public long salary();
public java.util.Map<java.lang.String, java.lang.String> addresses();
}
#

# javac —abilita–anteprima –fonte 14 EmpRecord.java
# javap EmpRecord
Se desideri ulteriori dettagli interni, esegui il comando javap con l’opzione -v.
- A Record class is final, so we can’t extend it.
- # javap -v EmpRecord
- Punti importanti sulle classi Record
- Le classi Record estendono implicitamente la classe
java.lang.Record
. - A single constructor is created with all the fields specified in the record definition.
- Tutti i campi specificati nella dichiarazione del record sono finali.
- I campi del record sono immutabili in modo “superficiale” e dipendono dal tipo. Ad esempio, possiamo modificare il campo degli indirizzi accedendo ad esso e quindi apportando aggiornamenti.
La classe Record fornisce automaticamente metodi di accesso per i campi. Il nome del metodo è lo stesso del nome del campo, a differenza dei metodi getter generici e convenzionali.
La classe Record fornisce anche implementazioni per hashCode(), equals() e toString().
package com.journaldev.java14;
public class RecordTest {
public static void main(String[] args) {
EmpRecord empRecord1 = new EmpRecord(10, "Pankaj", 10000, null);
EmpRecord empRecord2 = new EmpRecord(10, "Pankaj", 10000, null);
Utilizzo dei Record nel Programma Java
System.out.println(empRecord1);
Diamo un'occhiata a un esempio semplice dell'uso della nostra classe EmpRecord.
System.out.println("Name: "+empRecord1.name());
System.out.println("ID: "+empRecord1.id());
// toString()
System.out.println(empRecord1.equals(empRecord2));
// accesso ai campi
System.out.println(empRecord1 == empRecord2);
}
}
// equals()
EmpRecord[id=10, name=Pankaj, salary=10000, addresses=null]
Name: Pankaj
ID: 10
true
false
// hashCode()
Output:
L’oggetto Record funziona allo stesso modo di qualsiasi classe modello, oggetto dati, ecc.
public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {
public EmpRecord {
if (id < 0)
throw new IllegalArgumentException("employee id can't be negative");
if (salary < 0)
throw new IllegalArgumentException("employee salary can't be negative");
}
}
Estensione del Costruttore dei Record
EmpRecord empRecord1 = new EmpRecord(-10, "Pankaj", 10000, null);
A volte, vogliamo avere delle validazioni o dei registri nel nostro costruttore. Ad esempio, l’id dell’impiegato e lo stipendio non dovrebbero essere negativi. Il costruttore predefinito non avrà questa validazione. Possiamo creare un costruttore compatto nella classe record. Il codice di questo costruttore verrà posizionato all’inizio del costruttore generato automaticamente.
Exception in thread "main" java.lang.IllegalArgumentException: employee id can't be negative
at com.journaldev.java14.EmpRecord.<init>(EmpRecord.java:9)
Se creiamo un EmpRecord come nel seguente codice:
Otterremo un’eccezione in fase di esecuzione come:
public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {
public int getAddressCount() {
if (this.addresses != null)
return this.addresses().size();
else
return 0;
}
}
Le classi dei record possono avere metodi?
Sì, possiamo creare metodi nei record.
Ma, i record sono pensati per essere portatori di dati. Dovremmo evitare di avere metodi di utilità in una classe di record. Ad esempio, il metodo sopra può essere creato in una classe di utilità.
Se pensi che avere un metodo sia necessario per la tua classe Record, rifletti attentamente se hai davvero bisogno di una classe Record?
Source:
https://www.digitalocean.com/community/tutorials/java-records-class