Please don't do that.
Don't replace classes with records just because "it's less verbose". This is technically wrong and poor engineering.
The JEP 395 explicitly states that :
"While records do offer improved concision when declaring data carrier classes, it is not a goal to declare a "war on boilerplate". In particular, it is not a goal to address the problems of mutable classes which use the JavaBeans naming conventions."
(
openjdk.org/jeps/395)
Why is it wrong ?
The notion of identity is important in OOP. A class is perfect to model something that has a stable identity despite some of its characteristics changing over time.
For example, a Person might be identified by her name or SSN. Then, her age, address or hair color might change, without changing her identity.
Same for a bank account: its balance might change over time, but it's still the same account, defined by its accountId.
Having a stable identity is very important in many circumstances, for example when the instance is used as a Map key, or put into a HashSet.
Records don't allow this. Their component values define their identity. If you model a bank account with a record, anytime you withdraw some cash, it becomes another bank account.
Or, in Josh's example, anytime an Order is added to the Cart, the Cart identity will change and become another Cart.
Records are fine for DTOs though (they won't be mutated anymore at this point, and probably not put into Hash* collections), or to model "multi-component value types", such as a Point3D(int x, int y, int z).
So what should I use ?
Use classes to model complex, mutable objects where not all fields define the object's identity.
Ex: User, Order...
Also, the presence of annotations on fields is generally a strong hint to use a class.
Use records to aggregate multiple immutable values togegther, where changing a single value changes the whole agregate's identity.
Think "composite prilitive type".
Ex: Point2D, Address, Date.
Make the right choice based on real technical reasons, not merely on perceived verbosity.
I don’t know when the last time I created a setter is. I use constructors. I try to whenever possible let Java records create the getters, if I have internal state I want the consumer of a type to have access to. And I don’t make types public, most of the time.
record Cart(
@Id int id, String sessionId, Set<Orders> orders){}
it doesn’t get more concise than that