As a general rule of thumb, you want to be as restrictive as possible
on your class properties and extension points (private > protected > public). This is particularly important in projects that run for a long period of time and need maintenance and re-factoring.
It's quite difficult to restrict your properties from public to protected/private once they have been used for a while, because you don't know how many other classes are relying on those properties being public. On the other hand, relaxing from private to protected/public is less traumatic because you don't have to worry about previous access to that property from without that class.
Having said that, getters and setters provide you with unique points of contact to interact with private members of a class. That's called encapsulation
in OOP. That means that you can ensure that everyone that interacts with those properties are doing it in the same and consistent manner. A silly example would be normalization of the property:
private String name;
public void setName(String name) {
this.name = StringUtils.capitalize(name);
}
You're ensuring here that whoever sets a name does not need to care about its capitalization, because you're enforcing it through the setter. Same could apply to a getter, applying business rules as needed.
Compare that with accessing a public property which you then need to capitalize on your end every time you use it...
Finally, I'd say that blindly adding getters and setters to your objects is a bad practice
. Only provide those accessors when there's a good reason for them to exist. For instance:
class Person {
private name;
public Person(String name) {
this.name = name
}
public String name() {
return name;
}
}
You normally don't set the name to a person, so we can omit that setter all together. But every person has a name. That being the case, you can enforce it via its constructor. This makes that distinction explicit, enhancing your design and preventing your object from being in a non-consistent state.