I do not know exactly what you meant by semantics , but we can see the issue from various perspectives.
Clarity
Using setter methods can be more confusing because someone else will read your code.
It may incorrectly assume that the setter method performs some logic within it, so it needs to navigate to the methods and look at what they do.
Notice in the other answers that they always end up inferring something or putting a condition. Imagine a system with multiple cases of this and you can extrapolate how much complexity this will add to everyone's life.
Always use the simplest solution. In this case, always use direct assignment when possible.
I imagine this may seem "ugly" to some, especially since when we first start using object orientation, we get the impression that any direct manipulation of attributes somehow breaks the encapsulation.
But the class scope is owned by itself. A class does not need secrets for itself, or we begin to embark on insanity. Could we say that a class that encapsulates itself has multiple personalities?
Effect
Imagining now that the setters only assign, the final effect would be the same as the assignment. However, this is not always so simple, especially where there is competition involved.
Understand competition as the act of accessing and modifying a single attribute or object from different threads at the same time.
In concurrent scenarios, you should always use the final
or volatile
modifiers, as they ensure that the state of the variables will be written to main memory and all threads will see the value right. Otherwise a thread can read the old value cached.
An efficient way to share objects between threads is by using immutable objects. In this case, it is recommended that you use final
on all attributes. Example:
private final String nome;
private final float n1;
In the example above, the final
attributes can only be assigned once and this must occur until the builder runs. Attributes final
can not have delegated assignment to a setter .
Maintenance and avoiding silly errors
In addition to attributes, we can also declare the parameters as final
, that is, they can not have the value changed. Example:
public Aluno(final String n, final float n1, final float n2) {...}
What does this help?
First, you avoid silly errors like:
public Aluno(String nome, float nota1, float nota2) {
this.nome = nome;
this.nota1 = nota1;
nota2 = nota2;
}
Believe me, I have already corrected silly mistakes like this one up in production many times. This would be avoided if the parameters were final
:
public Aluno(final String nome, final float nota1, final float nota2) {
this.nome = nome;
this.nota1 = nota1;
nota2 = nota2; //erro de compilação aqui
}
This also helps to remember that you should not modify method parameters to reuse it as a variable, as if this would save memory or something.
Running logic
If there is a need to run some logic in the setter method, I suggest an alternative:
public Aluno(String nome, float nota1, float nota2) {
this.nome = nome;
this.nota1 = verificarNotaValida(nota1);
this.nota2 = verificarNotaValida(nota2);
}
public void setNota1(float nota1) {
this.nota1 = verificarNotaValida(nota1);
}
Extracting the validation logic allows more reuse and leaves the code clear.