Java Getters and Setters: Encapsulation, Validation and Best Practices

0

Getters and setters are methods used to control access to the private fields of a Java class. A getter typically reads a value, while a setter updates it. They are closely associated with encapsulation because they allow a class to protect its internal state instead of exposing fields directly.

Consider a bank account. You should be able to ask for the current balance, but you should not be able to directly replace the balance with an arbitrary value. A getter can provide controlled read access, while a setter or domain-specific method can control how the value changes.

Getters and setters provide controlled access to private fields. They are useful, but creating one automatically for every field is not always good design.

Why Do Getters and Setters Exist?

Java classes commonly keep fields private to prevent other classes from changing their internal state directly. However, other parts of the application may still need to read or modify some of those values.

Getters and setters provide a controlled doorway between the object's internal data and external code.

Basic Getter Syntax

public dataType getFieldName() {
    return fieldName;
}

A getter usually returns the value of a private field. The method name commonly begins with get, followed by the field name with its first letter capitalized.

Basic Setter Syntax

public void setFieldName(dataType value) {
    this.fieldName = value;
}

A setter usually accepts a value and assigns it to the corresponding private field. The method name commonly begins with set.

Simple Getter and Setter Example

class Student {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

The name field remains private. External code cannot access it directly, but it can use getName() and setName() to interact with the object.

public class Main {

    public static void main(String[] args) {

        Student student = new Student();

        student.setName("Anita");

        System.out.println(student.getName());
    }
}

The setter stores the name, and the getter retrieves it. The Main class never accesses the private field directly.

How Getters Work

A getter is usually a read operation. It retrieves the current value stored inside the object.

class Product {

    private double price = 999.99;

    public double getPrice() {
        return price;
    }
}

External code can retrieve the price by calling getPrice(). It does not need direct access to the price field.

How Setters Work

A setter is usually a write operation. It receives a new value and updates the corresponding field.

class Product {

    private double price;

    public void setPrice(double price) {
        this.price = price;
    }
}

The this keyword distinguishes the object's field from the method parameter.

Why Validation Belongs in Setters

One of the biggest advantages of a setter over a public field is that the class can validate the incoming value before changing its state.

class Product {

    private double price;

    public void setPrice(double price) {

        if (price >= 0) {
            this.price = price;
        }
    }

    public double getPrice() {
        return price;
    }
}

Now negative prices are rejected. If price were a public field, external code could assign a negative value directly without giving the class an opportunity to validate it.

A setter is not merely a storage mechanism. It can become a controlled checkpoint where validation, normalization, or business rules are applied.

Getter Without Setter

A field does not always need both a getter and a setter. Sometimes other classes should be able to read a value but should not be allowed to change it directly.

class Employee {

    private final String employeeId;

    public Employee(String employeeId) {
        this.employeeId = employeeId;
    }

    public String getEmployeeId() {
        return employeeId;
    }
}

There is a getter, but no setter. The employee ID can be read after the object is created, but there is no public method for changing it.

Setter Without Getter

The reverse is also possible. Some values may need to be supplied to an object without being exposed afterward.

class SecurityService {

    private String securityToken;

    public void setSecurityToken(String token) {
        this.securityToken = token;
    }
}

In a real application, sensitive values would usually require additional security considerations, but the example demonstrates that a getter and setter do not have to appear as a pair.

Boolean Getters

Boolean fields commonly use an is prefix instead of get.

class User {

    private boolean active;

    public boolean isActive() {
        return active;
    }

    public void setActive(boolean active) {
        this.active = active;
    }
}

Calling user.isActive() reads naturally because the method represents a yes-or-no question.

Getters and Setters Are Not Always Necessary

A common beginner habit is to create a getter and setter for every private field. While IDEs can generate them quickly, that does not mean every field should expose both operations.

Suppose an Order object stores an internal calculation value. Exposing a setter may allow external code to change a value that should only be calculated by the Order itself.

class Order {

    private double total;

    public double getTotal() {
        return total;
    }

    public void addItem(double price) {
        if (price > 0) {
            total += price;
        }
    }
}

Here, exposing getTotal() makes sense because callers may need to know the total. A public setTotal() would be dangerous because it would allow callers to bypass the order's calculation rules.

Good encapsulation does not mean “private field plus getter plus setter.” It means exposing only the operations that make sense for the object's responsibilities.

Getters, Setters, and Encapsulation

Encapsulation is about controlling access to an object's state and behaviour. Getters and setters support this goal, but they do not automatically guarantee strong encapsulation.

For example, this class technically uses encapsulation:

class BankAccount {

    private double balance;

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }
}

However, the setter allows external code to replace the balance with any value. A better design may expose operations such as deposit() and withdraw() that enforce business rules.

class BankAccount {

    private double balance;

    public double getBalance() {
        return balance;
    }

    public void deposit(double amount) {

        if (amount > 0) {
            balance += amount;
        }
    }

    public boolean withdraw(double amount) {

        if (amount > 0 && amount <= balance) {
            balance -= amount;
            return true;
        }

        return false;
    }
}

This design exposes useful behaviour rather than exposing unrestricted state modification.

Common Beginner Mistakes

  • Making every private field automatically accessible through both a getter and setter.
  • Putting validation outside the class and allowing invalid values through setters.
  • Using public setters when a business operation would provide better control.
  • Forgetting that getters can expose mutable objects or collections that callers can modify indirectly.
  • Assuming getters and setters alone guarantee complete encapsulation.

Best Practices

  • Keep fields private.
  • Provide getters only when external code genuinely needs to read a value.
  • Provide setters only when external code should legitimately change a value.
  • Validate values inside setters when setters are appropriate.
  • Prefer meaningful domain methods such as deposit(), withdraw(), activate(), or cancel() when they better represent the object's behaviour.
  • Be careful when returning mutable objects or collections from getters.

Interview Insights

A common interview question is: “Why are getters and setters used in Java?” A strong answer is that they provide controlled access to private fields and allow a class to apply validation, maintain invariants, and change its internal implementation without exposing the fields directly.

Another useful interview point is that getters and setters are not synonymous with good encapsulation. If every internal field receives an unrestricted getter and setter, the class may still expose too much of its internal state.

Quick Revision

Concept Key Point
Getter Usually reads and returns the value of a private field.
Setter Usually changes a private field through a controlled method.
Validation Can be performed inside setters before changing state.
Read-only field Can expose a getter without providing a setter.
Boolean getter Commonly uses the is prefix, such as isActive().
Encapsulation Getters and setters can support controlled access but should not expose unnecessary state.

Getters and setters are simple methods, but their real value lies in the control they give a class over its state. The goal is not to hide fields merely for the sake of using private; the goal is to decide deliberately how other objects should interact with the class. Sometimes that means a getter, sometimes a validated setter, and sometimes a completely different business method that expresses the object's behaviour more naturally.

Post a Comment

0Comments
Post a Comment (0)