100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace

Getters and Setters: Best Practices

Best practices for getters and setters in OOP — validation, defensive copies, and when to omit a setter — with a Java example.

mediumQ145 of 226 in Object Oriented Programming Est. time: 5 minsLast updated:
Open Code Lab

Expected Interview Answer

Good getter/setter practice means not generating them blindly for every field, but instead validating input in setters, returning defensive copies of mutable fields from getters, omitting setters for fields that should be immutable, and naming methods so the exposed behavior matches what the class actually guarantees.

A common anti-pattern is auto-generating a public getter and setter for every field, which effectively makes the class as unsafe as if the fields were public — it defeats the purpose of encapsulation because it exposes both read and write access with no validation or invariant protection. Better practice: only add a setter if external mutation is genuinely needed; validate every setter input against business rules and throw on violation; keep getters free of side effects and have them return defensive copies for mutable types (Date, List, arrays) rather than live internal references; prefer constructing objects fully valid via the constructor and using immutability where the domain allows it; and avoid “anemic” getter/setter-only classes that push all behavior into external service classes, which is itself considered a design smell (Tell, Don’t Ask is the corrective principle).

  • Preserves real invariant protection instead of just adding indirection
  • Prevents accidental external mutation of shared internal state
  • Keeps object behavior colocated with its data
  • Makes intent explicit: read-only fields simply have no setter

AI Mentor Explanation

A responsible team doesn’t hand every fan a pen to edit the official scoresheet just because it’s convenient — only the accredited scorer gets write access, and only through the validated recording process. Blindly giving everyone read-and-write access to everything is exactly the anti-pattern good practice avoids: some things (like the match date once play starts) should have no “setter” at all. Good getter/setter design mirrors this selective, validated access rather than universal open access.

Step-by-Step Explanation

  1. Step 1

    Question whether a setter is needed at all

    Prefer full initialization via the constructor; only add a setter if genuine external mutation is required.

  2. Step 2

    Validate every setter

    Enforce business rules and throw on invalid input rather than blindly assigning.

  3. Step 3

    Keep getters side-effect free and defensive

    Return computed or copied values for mutable field types rather than live internal references.

  4. Step 4

    Avoid anemic, auto-generated pairs

    Do not generate a public getter/setter for every field by rote — that reintroduces the exposure encapsulation is meant to prevent.

What Interviewer Expects

  • Recognition that blanket getter/setter generation defeats encapsulation
  • Concrete validation logic mentioned for setters, not just assignment
  • Awareness of defensive copying for mutable getter return types
  • Understanding of when a field should have no setter at all (immutability)

Common Mistakes

  • IDE-generating getters and setters for every field without judgment
  • Setters that assign without any validation
  • Getters that leak a live reference to an internal mutable collection or date
  • Believing all classes must expose both a getter and a setter for every field

Best Answer (HR Friendly)

Best practice with getters and setters isn’t to add them automatically for every field — that just exposes the field with extra steps. I validate setter input against real business rules, keep getters free of side effects, return defensive copies for mutable fields like dates or lists, and simply don’t add a setter for anything that should stay fixed after construction.

Code Example

Validated setter, defensive getter, and a deliberately absent setter
import java.util.Date;

public class Employee {
    private final String employeeId; // fixed at construction: no setter
    private final Date hireDate;      // immutable after hire: no setter
    private double salary;

    public Employee(String employeeId, Date hireDate, double salary) {
        this.employeeId = employeeId;
        this.hireDate = new Date(hireDate.getTime()); // defensive copy in
        setSalary(salary); // validated even at construction
    }

    public String getEmployeeId() { return employeeId; }

    public Date getHireDate() {
        return new Date(hireDate.getTime()); // defensive copy out
    }

    public double getSalary() { return salary; }

    // Setter is exposed only where real mutation is needed, and it validates
    public void setSalary(double newSalary) {
        if (newSalary < 0) {
            throw new IllegalArgumentException("Salary cannot be negative");
        }
        this.salary = newSalary;
    }
}

Follow-up Questions

  • Why is auto-generating getters and setters for every field considered an anti-pattern?
  • How do you decide whether a field should have a setter at all?
  • What is a defensive copy and why does it matter for getters returning mutable types?
  • How does the "Tell, Don’t Ask" principle relate to getter/setter overuse?

MCQ Practice

1. What is the main risk of blindly generating a public getter and setter for every field?

Unvalidated getters and setters for every field give external code the same unrestricted access as public fields would.

2. A getter returning a mutable field (like a Date) should?

Returning a defensive copy prevents external code from mutating the object’s internal state through the returned reference.

3. When should a field deliberately have no setter?

Fields that should not change after object creation should have no setter, enforcing immutability by design.

Flash Cards

Biggest getter/setter anti-pattern?Auto-generating a public pair for every field with no validation, defeating encapsulation.

What should a setter always do?Validate input against real business rules before assigning.

What should a getter avoid?Side effects, and leaking live references to mutable internal state.

When to omit a setter entirely?When the field should remain immutable after construction.

1 / 4

Continue Learning