1. What are getters and setters
If you think of an object as a safe, its private fields are the contents of the safe, and getters and setters are the keys to individual boxes. Getters let you see what’s inside, and setters let you carefully put something new in there (but only if you don’t put, say, a hedgehog instead of documents).
Getter
A getter is a public method (public) that returns the value of a private field (private). Its name typically starts with get + the field name with an initial capital letter.
public class Person {
private String name; // Private field
// Getter for the name field
public String getName() {
return name;
}
}
Setter
A setter is a public method (public) that allows you to change the value of a private field. Its name starts with set + the field name with an initial capital letter.
public class Person {
private String name;
// Setter for the name field
public void setName(String name) {
this.name = name;
}
}
For boolean fields
For fields of type boolean, it’s customary to use the is prefix in getters:
private boolean active;
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
2. Syntax and naming conventions
Java is a strict language, but not a killjoy. There are well-established conventions that make your code understandable to other developers (and to yourself a month later).
- Getter: public Type getFieldName()
- Setter: public void setFieldName(Type value)
- Getter for boolean: public boolean isFieldName()
The field name part in the method is capitalized: if the field is age, then the methods will be getAge() and setAge().
This convention follows the JavaBeans style, thanks to which IDEs, libraries, and frameworks can automatically discover your getters and setters. For example, if you use Spring or JavaFX, these methods will be called “magically” when needed.
3. Code examples
Let’s take a learning project—a simple “contacts” app (a phonebook analogue)—and add proper getters and setters.
Example: Contact class with private fields and getters/setters
public class Contact {
private String name;
private String phone;
private int age;
private boolean favorite;
// Getters
public String getName() {
return name;
}
public String getPhone() {
return phone;
}
public int getAge() {
return age;
}
public boolean isFavorite() {
return favorite;
}
// Setters
public void setName(String name) {
this.name = name;
}
public void setPhone(String phone) {
this.phone = phone;
}
public void setAge(int age) {
// Validation example: age must not be negative
if (age < 0) {
System.out.println("Age cannot be negative!");
return;
}
this.age = age;
}
public void setFavorite(boolean favorite) {
this.favorite = favorite;
}
}
Usage in the application
Contact friend = new Contact();
friend.setName("Ivan Ivanov");
friend.setPhone("+1-999-123-45-67");
friend.setAge(25);
friend.setFavorite(true);
System.out.println("Name: " + friend.getName());
System.out.println("Phone: " + friend.getPhone());
System.out.println("Age: " + friend.getAge());
System.out.println("Favorite: " + (friend.isFavorite() ? "Yes" : "No"));
Validation example in a setter
Note that in the setAge setter we added a simple check: if the age is negative, we don’t change the field and print a warning. This is a simple way to protect an object from invalid data.
4. Best practices: how to do it right
Not every field should have a public setter
Sometimes a field should be read-only—for example, a unique identifier that’s set when the object is created and never changes. In that case, you simply don’t write a setter:
public class Contact {
private final int id; // final: cannot be changed after initialization
public Contact(int id) {
this.id = id;
}
public int getId() {
return id;
}
// No setId!
}
Use getters/setters for access control and validation
public void setName(String name) {
if (name == null || name.trim().isEmpty()) {
System.out.println("Name cannot be empty!");
return;
}
this.name = name;
}
Do not expose internal mutable objects directly
If you have a field—for example, an array of phone numbers:
private String[] phones;
Don’t return it directly via a getter:
public String[] getPhones() {
return phones; // Bad!
}
Such code allows external code to modify the array arbitrarily—breaking encapsulation!
Better: return a copy of the array:
public String[] getPhones() {
return Arrays.copyOf(phones, phones.length); // Return a copy
}
Or just clone it:
public String[] getPhones() {
return phones.clone();
}
Keep getters and setters clear and simple
- Don’t write complex business logic in getters/setters—their job is simple: access control and, if necessary, validation.
- If a field shouldn’t change, don’t provide a setter at all.
- If a field shouldn’t be accessible from outside, don’t provide a getter.
5. Automatic generation of getters/setters in IDEs
Writing accessors by hand is not much fun, especially if a class has a dozen fields. Fortunately, modern IDEs (for example, IntelliJ IDEA, Eclipse, VS Code with plugins) can generate them automatically.
In IntelliJ IDEA
- Open the class and put the cursor inside the class body.
- Press Alt + Insert (or Code -> Generate...).
- Select Getter and Setter.
- Check the desired fields and click OK.
Voilà! Your getters and setters will appear as if by magic.
In Eclipse
- Open the class.
- Right-click — Source — Generate Getters and Setters...
- Select the fields and click OK.
In VS Code (with Java Extension Pack)
- Open the class file.
- In the Command Palette (Ctrl+Shift+P), type Generate getters and setters.
- Follow the prompts.
6. Evolving your application: encapsulation in action
In previous lectures, you built a simple contacts app. Now we can improve it by making fields private and exposing access only through getters/setters.
Before (bad example):
public class Contact {
public String name;
public String phone;
public int age;
}
The problem: any code can do this:
Contact c = new Contact();
c.age = -1000; // Now we have a vampire in the phonebook!
After (good example):
public class Contact {
private String name;
private String phone;
private int age;
public void setAge(int age) {
if (age < 0) {
System.out.println("Age cannot be negative!");
return;
}
this.age = age;
}
public int getAge() {
return age;
}
// Other getters/setters...
}
Now it’s impossible to accidentally (or deliberately) break the object from the outside.
7. Getters/setters for computed and immutable properties
Sometimes a value isn’t stored in a field but computed on the fly:
public class Rectangle {
private int width;
private int height;
public int getArea() {
return width * height;
}
}
No setter is needed for the area—you can’t set it directly, only change the width or height.
8. Getters and setters: common mistakes
Mistake #1: A getter/setter breaks encapsulation.
If a getter returns a reference to an internal mutable object (for example, a list), external code can change it, bypassing all checks. This undermines the idea of encapsulation.
Mistake #2: A setter doesn’t validate data.
If a setter simply assigns a value without checking it, the object can end up in an invalid state (for example, a negative age or an empty name).
Mistake #3: Automatically generating setters for all fields.
An IDE can generate setters for all fields, but that isn’t always right! For an identifier (id), for example, you don’t need a setter.
Mistake #4: Complex logic in getters/setters.
Getters and setters should be simple. If complex business logic appears in them, consider moving it to separate methods.
Mistake #5: Violating naming conventions.
If you name a getter fetchName() instead of getName(), some frameworks and libraries won’t be able to recognize it.
GO TO FULL VERSION