0% found this document useful (0 votes)
98 views

Stop Using Setters PDF

The document discusses the disadvantages of using setters in object-oriented programming. It provides examples of how setters allow objects to be mutated unexpectedly, which can lead to bugs. Setters make objects mutable and their state unpredictable. Instead, the author argues that objects should be initialized fully in the constructor and then made immutable.

Uploaded by

Yaegar Wain
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
98 views

Stop Using Setters PDF

The document discusses the disadvantages of using setters in object-oriented programming. It provides examples of how setters allow objects to be mutated unexpectedly, which can lead to bugs. Setters make objects mutable and their state unpredictable. Instead, the author argues that objects should be initialized fully in the constructor and then made immutable.

Uploaded by

Yaegar Wain
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1

Sign in Get started

WRIT E FOR US CODING INT ERVIEW COURS E →

You have 2 free stories left this month. Sign up and get an extra one for free.

Stop Using Setters


Semyon Kirekov Follow
May 14 · 3 min read

Setters-pattern is one the one most popular in lots of programming


languages. Engineers have been using it for such a long time that this
approach has become obvious. Even IDE’s now can generate setters for
you just by clicking a few hotkeys. I think that setters usage is the one
thing that should be avoided in any case. This entry contains code
snippets on Java, but these rules can be applied to any other language.

Image by PublicDomainPictures from Pixabay

I bet that everyone has seen something like that.

1 class Person {
2 private int age;
3 private String firstName;
4 private String lastName;
5 // getters and setters...
6 }
7
8 Person employee = new Person();
9 employee.setAge(25);
10 employee.setFirstName("Michael");
11 employee.setLastName("Brown");

SettersExample.java hosted with ❤ by GitHub view raw

Setters usage example in Java

This approach seems quite elegant, but let’s think about it. Firstly, we
instantiate an empty object which has nothing inside it. After that we
assign required values step by step. What if we forgot to assign the first
name or the age? That means that future executions would handle an
incomplete object. More than that, setters presence means that object is
mutable and can be modified by anyone at any time. Let’s see another
example.

1 Person manager = new Person();


2 employee.setAge(32);
3 employee.setFirstName("Ellen");
4 employee.setLastName("Green");
5
6 List<Person> engineers = humanResources.findAllSubordinates(manager);
7 // some other actions with manager ...

PassedMutableObject.java hosted with ❤ by GitHub view raw

Passing a mutable entity to another method

We do not expect any mutations on manager by calling


findAllSubordinates , but how can we know that? In this case,
humanResources can be just an interface. We have no idea how exactly
does it work. So, we are not aware of manager future state, because its
public API contains mutating methods that can be called.

Perhaps this argument might be not convincing enough. So, let’s see
another example. Suppose we have a map of employees with their
payment rates.

1 Person jack = new Person();


2 jack.setName("Jack");
3 jack.setAge(23);
4
5 Person julia = new Person();
6 julia.setName("Julia");
7 julia.setAge(35);
8
9 Map<Person, Integer> map = new HashMap<>();
10 map.put(jack, 35);
11 map.put(julia, 65);
12
13 System.out.println("Map: " + map);
14 jack.setAge(55); // key corrupting
15 System.out.println("Corrupted map: " + map);
16 System.out.println("Jack's rate: " + map.get(jack));
17 System.out.println("Julia's rate: " + map.get(julia));

MutatedMap.java hosted with ❤ by GitHub view raw

Unexpected map corrupting

And the output is

Map: {[name=Jack, age=23]=35, [name=Julia, age=35]=65}


Corrupted map: {[name=Jack, age=55]=35, [name=Julia, age=35]=65}
Jack's rate: null
Julia's rate: 65

That happens because new Jack’s hash-code is not equal to the one that
is containing on the map. So, the keys are considered different. There is
a hack that can fix this situation, but it deserves another story.

Edit: Person has to implement equals and hashCode methods. Otherwise,


Jack’s rate shall be 35 as expected, because the default hashCode

implementation returns the same value even if you changed some field
values. Thanks tw-abhi for pointing!

By the way, I have also seen people using setters with dependency
injection in frameworks like Spring. Check this out.

1 @Component
2 class ParentService {
3 ...
4 @Autowired
5 public void setChildService(ChildService childService) {
6 this.childService = childService;
7 }
8 }
9
10 @Component
11 class MyService {
12 private ParentService parentService;
13 ...
14 public void corruptTheRuntime() {
15 parentService.setChildService(null);
16 }
17 }

DIWithSetters.java hosted with ❤ by GitHub view raw

Spring dependency injection with setter

Nobody expects that ParentService ’s dependency will suddenly


disappear. But as you can see, this can be easily done even without
Reflection API. My point is that if your class has methods that can mutate
its state, this may lead to unpleasant consequences.

Anyway, what can we do about it? Well, the easiest thing is passing all the
required values to the constructor.

1 class Person {
2 private final int age;
3 private final String firstName;
4 private final String lastName;
5
6 public Person(int age, String firstName, String lastName) {
7 this.age = age;
8 this.firstName = firstName;
9 this.lastName = lastName;
10 }
11 // getters...
12 }
13
14 Person mary = new Person(25, "Mary", "Watson");

PersonWithConstructor.java hosted with ❤ by GitHub view raw

Instantiating an immutable object with the constructor

Do you see that all properties are final now? It is very important. It
means that values can be assigned only once within the constructor
scope. Immutability assures us of the object’s constant state. We can pass Top highlight

it to any methods. We can even access it from multiple threads safely.

“But what if needed default values?”. Well, Java doesn’t support default
argument values, but we can define multiple constructors with some
parameters omitted. Or we can use Builder-pattern. We can implement it
ourselves, but I prefer to use the Lombok library.

1 // augo-generated builder and getters


2 @Builder
3 @Getter
4 class Person {
5 private final int age;
6 private final String firstName;
7 @Builder.Default
8 private final String lastName = "Brown";
9 }
10
11 Person mary = Person.builder()
12 .age(25)
13 .firstName("Mary")
14 .lastName("Watson")
15 .build();

PersonWithBuilder.java hosted with ❤ by GitHub view raw

Using builder in order to replace default arguments values

So, now it is obvious which parameter is assigned. This approach may


seem similar to setters usage, but there is a huge difference. We do not
instantiate an object until build method call. But once it is created it is
immutable.

Sometimes developers use builders to replace big constructors. This


might seem useful because it makes code cleaner and more intuitive, but
you should pay attention to such cases. Let’s have a look.

1 @Getter
2 @AllArgsContrustor
3 @Builder
4 class ReallyHugeClass {
5 private final int param1;
6 private final int param2;
7 ...
8 private final int param10;
9 }
10
11 // Too many arguments. Hard to read and maintain.
12 ReallyHugeClass hugeness = new ReallyHugeClass(1, 32, 12, ..., 231);
13 // Much better now
14 ReallyHugeClass otherHugeness = ReallyHugeClass.builder()
15 .param1(1)
16 .param2(32)
17 .param3(12)
18 ...
19 .param10(231);

ReallyBigConstructor.java hosted with ❤ by GitHub view raw

Using builder to replace the large constructor

The thing is that the second approach is significantly easier to


understand, but it is also easy to forget about some arguments. This
happens frequently especially if a class has been enhanced with new
parameters. Sometimes it’s acceptable, sometimes it’s not. Don’t forget
that the original purpose of the Builder-pattern is implementing default
argument values, but not to replace large constructors. If your class does
have many dependencies and all of them are required, it would be better
to split the class into several ones.

Conclusion
I hope that I convinced you that setters usage is not a good practice.
There are some situations when we have to use setters. For example, if
one library provides us with such API. But don’t use them in your
projects. It’s not worth it. Thank you for reading!

Resources
Reflection API

Builder-pattern

Lombok

Sign up for "Top Stories" from Level Up Coding


A monthly summary of the best stories shared in Level Up Coding

Create a free Medium account to get "Top Stories" in


Get this newsletter your inbox.

Java Software Development Patterns Best Practices Programming

277 claps

WRIT T EN BY

Semyon Kirekov Follow

Full-stack developer (Java and React). Passionate about clean


code, tea, pastila and smooth jazz and blues.
[email protected]

Level Up Coding Follow

Coding tutorials and news. The developer homepage


gitconnected.com

See responses (5)

More From Medium

Linux user tries My Top 20 VS Code Tricky Java Interview 5 T hings T hat Are Hard
Windows, in 2020 Extensions Questions To Grasp When You
Dominik Tarnowski in Level Up Neo Hao Jun in Level Up Manusha Chethiyawardhana in Start Programming
Coding Coding Level Up Coding Daan in Level Up Coding

5 Lessons I’ve Learned 4 JavaScript Tricks You SOLID Principles — 3 Habits T hat Will Help
on How to Structure Should Know Simpli ed with You Become a Top
Code Anupam Chugh in Level Up Illustrations Developer
Daan in Level Up Coding Coding Animesh Gaitonde in Level Up Manish Jain in Level Up Coding
Coding

Discover Medium Make Medium yours Become a member


Welcome to a place where words matter. On Medium, smart Follow all the topics you care about, and we’ll deliver the Get unlimited access to the best stories on Medium — and
voices and original ideas take center stage - with no ads in best stories for you to your homepage and inbox. Explore support writers while you’re at it. Just $5/month. Upgrade
sight. Watch

About Help Legal

You might also like