Regular Java Class (Before Java 16)
public class User {
private final String name;
private final int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return age == user.age && name.equals(user.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "User{name='" + name + "', age=" + age + '}';
}
}
This works — but it’s a lot of code just to hold data.
Java Record (Java 16+)
public record User(String name, int age) {}
That’s it! Java will auto-generate:
-
getName() -
getAge() -
Constructor
-
equals(),hashCode(), andtoString()
Usage Example (Same for both)
User user1 = new User("Alice", 25);
User user2 = new User("Alice", 25);
System.out.println(user1.name()); // "Alice"
System.out.println(user1.equals(user2)); // true
System.out.println(user1); // User[name=Alice, age=25]
Note: In records, you use
name()instead ofgetName().
Summary
- Used to store data in a simple way.
- Good for DTOs, value objects, and small data structures.
- Reduces boilerplate code like constructors, getters,
equals(), etc.
| Feature | Class | Record |
|---|---|---|
| Boilerplate | Lots of code | One-liner |
| Immutability | Manual | Default |
| Inheritance | Allowed (extends) | Not allowed (only implements) |
| Use Case | General purpose | Data-only classes |
class Animal {}
record Dog(String name) extends Animal {} // ERROR
interface Animal {
void sound();
}
record Dog(String name) implements Animal {
@Override
public void sound() {
System.out.println("Woof!");
}
}