Question
Why Use Getters and Setters in Java? Accessors vs Public Fields
Question
In Java, what is the advantage of using getters and setters that only read and write a value, instead of simply exposing a public field?
For example, why would this:
public String foo;
be considered worse than this:
private String foo;
public void setFoo(String foo) {
this.foo = foo;
}
public String getFoo() {
return foo;
}
If a getter or setter does more than a simple read or write, the benefit is easy to understand. What is less clear is why plain pass-through getters and setters are often preferred, even though public fields require much less boilerplate.
Short Answer
By the end of this page, you will understand why Java developers often prefer private fields with getters and setters over public fields, even when the methods appear to do nothing extra. You will learn the core idea of encapsulation, how it protects your code from future changes, when public fields are acceptable, and how this choice affects maintainability in real projects.
Concept
In Java, the main idea behind getters and setters is encapsulation.
Encapsulation means an object should control access to its own internal state. Instead of letting other code directly read or write a field, the object exposes methods that define how that value is accessed.
At first, this may seem unnecessary when a getter just returns the field and a setter just assigns it:
private String foo;
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
That looks equivalent to:
public String foo;
But they are not equivalent in terms of design.
Why it matters
If you expose a public field:
- Any code can read it directly
- Any code can change it directly
- You cannot later add validation without changing all calling code
- You cannot control when it is read or written
- You tightly couple other code to your internal representation
If you expose methods instead:
- You can later add validation
- You can make the property read-only or write-only
- You can log access or trigger side effects later
- You can change internal storage without changing external code
- You preserve a stable public API
Mental Model
Think of a class like a building.
- A public field is like leaving the storage room door open so anyone can walk in and move things around.
- A getter is like a service window where people can ask to see something.
- A setter is like a controlled drop-off desk where items are accepted according to rules.
At first, the service window may feel unnecessary because the worker is just handing you the item with no questions asked. But later, the building can add rules:
- only allow certain items
- record who accessed them
- reject invalid deliveries
- move the storage room without changing the public-facing window
The window gives flexibility. The open door does not.
Syntax and Examples
Basic syntax
Public field
public class User {
public String name;
}
Usage:
User user = new User();
user.name = "Ava";
System.out.println(user.name);
Private field with getter and setter
public class User {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Usage:
User user = new User();
user.setName("Ava");
System.out.println(user.getName());
Step by Step Execution
Consider this class:
public class BankAccount {
private double balance;
public void setBalance(double balance) {
if (balance < 0) {
throw new IllegalArgumentException("Balance cannot be negative");
}
this.balance = balance;
}
public double getBalance() {
return balance;
}
}
And this code:
BankAccount account = new BankAccount();
account.setBalance(100.0);
System.out.println(account.getBalance());
What happens step by step
-
BankAccount account = new BankAccount();- A new
BankAccountobject is created.
- A new
Real World Use Cases
Getters and setters are commonly used when a class needs to protect or shape its data.
Common real-world scenarios
User input validation
user.setEmail("TEST@EXAMPLE.COM");
The setter can:
- reject
null - trim whitespace
- normalize case
- enforce format rules
Domain rules
In a payroll system:
employee.setSalary(50000);
The setter can ensure salary is not negative.
Read-only identifiers
A database entity may have an ID that should be readable but not changed freely:
order.getId();
No public setter is provided.
Derived or computed values
A getter can calculate a value instead of returning a stored field:
invoice.getTotal();
This may sum line items internally.
Lazy loading or formatting
A getter may load data only when needed or return a cleaned-up representation.
Framework compatibility
Many Java libraries and frameworks expect JavaBean-style accessors such as:
Real Codebase Usage
In real projects, developers use accessors as part of a broader design strategy.
Common patterns
Guard clauses in setters
Setters often validate early:
public void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
this.age = age;
}
This keeps invalid state out of the object.
Early returns in getters
A getter may return a fallback value:
public String getDisplayName() {
if (nickname != null && !nickname.isBlank()) {
return nickname;
}
return fullName;
}
Defensive copying
If a field is mutable, a getter may return a copy instead of the original:
public List<String> getTags() {
return new <>(tags);
}
Common Mistakes
1. Creating getters and setters for everything without thinking
Some beginners expose every field with both getter and setter automatically. That can weaken design.
For example, this class allows uncontrolled changes:
public class Account {
private double balance;
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
A better design may be:
public class Account {
private double balance;
public double getBalance() {
return balance;
}
public void deposit(double amount) {
if (amount <= 0) {
throw new ();
}
balance += amount;
}
}
Comparisons
Public fields vs getters/setters
| Approach | Pros | Cons | Best use |
|---|---|---|---|
public field | Very simple, less boilerplate | No control, no validation, harder to change later | Tiny internal data holders, constants, simple demos |
private field + getter/setter | Encapsulation, validation, flexibility, stable API | More boilerplate | Most object-oriented application code |
Getter only vs getter and setter
| Pattern | Meaning | Use case |
|---|---|---|
| Getter only | Read-only from outside | IDs, timestamps, calculated values |
| Getter + setter |
Cheat Sheet
Quick reference
Public field
public String name;
- Simple
- No validation
- No control over reads/writes
- Harder to change later without breaking callers
Private field with accessor methods
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
- Supports encapsulation
- Lets you add validation later
- Keeps internal representation hidden
- Works well with many Java frameworks
Common rules
- Use
privatefields by default - Add a getter if outside code needs to read the value
- Add a setter only if outside code should be allowed to change it
- Prefer meaningful methods like
deposit()orrenameTo()when behavior matters - Avoid exposing mutable internal objects directly
Naming conventions
getName()for most fields
FAQ
Why are getters and setters better than public fields in Java?
They support encapsulation. You can control access, validate input, and change implementation later without breaking calling code.
If a getter and setter only pass through the value, are they still useful?
Yes. Their main value is preserving flexibility for future changes and hiding internal representation.
Should every private field have a getter and setter?
No. Only expose what outside code actually needs. Some fields should be read-only, and some should stay completely internal.
Are public fields ever acceptable in Java?
Yes, sometimes. Common examples are public static final constants and very simple internal data holders.
Why not just make everything public for less boilerplate?
Because it makes your code harder to protect, validate, and evolve. Saving a few lines now can create larger maintenance problems later.
Is a setter always the right way to modify object state?
No. If the change has business meaning, a behavior method like deposit(), activate(), or markAsPaid() is often better.
Do Java frameworks prefer getters and setters?
Many do. JavaBean-style methods are commonly used by serializers, ORMs, UI tools, and dependency injection frameworks.
Mini Project
Description
Build a small UserProfile class that stores a username and age. The project demonstrates why private fields and accessors are useful by enforcing basic validation rules and exposing safe read access.
Goal
Create a class that prevents invalid data while still allowing other code to read and update allowed values through methods.
Requirements
- Create a
UserProfileclass with private fields forusernameandage. - Add getter methods for both fields.
- Add setter methods that reject an empty username and a negative age.
- In a
mainmethod, create aUserProfileobject and print its values. - Try at least one invalid update and handle the error.
Keep learning
Related questions
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Choosing a @NotNull Annotation in Java: Validation vs Static Analysis
Learn how Java @NotNull annotations differ, when to use each one, and how to choose between validation, IDE hints, and static analysis tools.
Convert a Java Stack Trace to a String
Learn how to convert a Java exception stack trace to a string using StringWriter and PrintWriter, with examples and common mistakes.