Getter and Setter Methods in Java
Getters and setters are the public methods that expose the state of a Java object while keeping its fields private. They're the foundation of encapsulation β the idea that an object controls how its state is accessed and modified.
Why not use public fields?
A public field is a one-way street to trouble:
public class Circle {
public double radius; // β public field
}
Circle c = new Circle();
c.radius = -5; // nonsense, but impossible to prevent
A private field behind a setter lets you validate:
public class Circle {
private double radius;
public double getRadius() { return radius; }
public void setRadius(double radius) {
if (radius < 0) throw new IllegalArgumentException("Radius must be >= 0");
this.radius = radius;
}
}
Naming convention
The JavaBeans convention is strict and matters β frameworks like Jackson, Spring, Hibernate and Gson detect properties by matching these patterns:
| Field type | Getter | Setter |
|---|---|---|
String name | getName() | setName(String) |
int age | getAge() | setAge(int) |
boolean active | isActive() (preferred) | setActive(boolean) |
Boolean enabled | getEnabled() | setEnabled(Boolean) |
The is prefix works only for primitive boolean, not Boolean.
A complete example
public class User {
private String name;
private int age;
private boolean active;
public User(String name, int age) {
setName(name); // reuse validation from the setter
setAge(age);
this.active = true;
}
public String getName() { return name; }
public void setName(String name) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("Name is required");
}
this.name = name;
}
public int getAge() { return age; }
public void setAge(int age) {
if (age < 0 || age > 150) {
throw new IllegalArgumentException("Invalid age: " + age);
}
this.age = age;
}
public boolean isActive() { return active; }
public void setActive(boolean active) { this.active = active; }
}
Generate them in your IDE
- IntelliJ IDEA: Alt + Insert β Getter and Setter
- Eclipse: right-click the field β Source β Generate Getters and Setters
- VS Code (Java Extension Pack): Ctrl + . β Generate Accessors
Skip the boilerplate with Lombok
If your team already uses Lombok, annotations generate accessors at compile time:
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class User {
private String name;
private int age;
private boolean active;
}
To exclude sensitive fields from generated methods (for example to prevent logging passwords):
@Getter @Setter
public class User {
private String name;
@Getter(AccessLevel.NONE) private String password; // no getter generated
}
Or use a record (Java 16+)
For immutable data classes, a record removes the need for getters/setters entirely:
public record User(String name, int age, boolean active) { }
User u = new User("Alice", 30, true);
u.name(); // "Alice" β no 'get' prefix
u.age(); // 30
u.active(); // true
Records are final, all fields are final, and you get equals, hashCode and toString for free. Add validation with a compact constructor:
public record User(String name, int age) {
public User {
if (age < 0) throw new IllegalArgumentException("Invalid age");
}
}
Common anti-patterns
Anemic domain model
A class with only getters and setters (no behaviour) pushes logic elsewhere. If User has a birthdate, put getAge() on the class as a computed method rather than exposing the birthdate and letting every caller compute age independently.
Setters everywhere by default
Most fields don't need to change after construction. Prefer immutable objects: final fields, no setters, all state supplied in the constructor. Records make this the default.
Returning the mutable internal collection
public List<String> getTags() { return tags; } // β caller can .add() and .remove()
Return an unmodifiable view:
public List<String> getTags() { return List.copyOf(tags); }
Summary
- Keep fields
private. - Follow the JavaBeans naming convention β frameworks depend on it.
- Validate in setters, not in callers.
- Prefer immutable objects and records over classes with many setters.
- Use Lombok if you must keep classic classes but want less boilerplate.
Good accessors are invisible: they expose exactly what's needed, enforce invariants, and let the rest of the codebase treat the object as a trustworthy black box.