The 30 second answer
A record, final in Java 16, is a short way to declare a class that just carries data. From one line, the compiler generates private final fields, a constructor, accessor methods, and equals, hashCode and toString based on all the fields. I use them for DTOs, value objects, map keys and returning several values. Validation goes in a compact constructor.
record Point(int x, int y) {}
record Money(long cents, String currency) {
Money { // compact canonical constructor
if (cents < 0) throw new IllegalArgumentException("negative");
Objects.requireNonNull(currency);
}
Money plus(Money o) { return new Money(cents + o.cents, currency); }
}
var p = new Point(1, 2);
p.x(); // accessor is x(), not getX()
p.equals(new Point(1, 2)); // trueRecords can implement interfaces and have static fields, static and instance methods, and nested types. They can also be declared locally inside a method. Records were previewed in Java 14 and 15 and became final in Java 16. Jackson and Spring Boot can bind JSON and configuration properties to records, which makes them a good fit for request and response DTOs.
Sources: JEP 395: Records, JLS 8.10 Record Classes