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 typeGetterSetter
String namegetName()setName(String)
int agegetAge()setAge(int)
boolean activeisActive() (preferred)setActive(boolean)
Boolean enabledgetEnabled()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.