If you expose all your attributes with getters/setters you are gaining just data structure which is still used in C or any other procedural language. It is not encapsulation and Lombok is just making to work with procedural code less painful. Getters/setters as bad as plain public fields. There is no difference really.
And data structure is not an object. If you will start creating an object from writing an interface you will never add getters/setters to the interface. Exposing your attributes leads to spaghetti procedural code where manipulation with data is outside of an object and spread allover the codebase. Now you are dealing with data and with manipulations with data instead of talking to objects. With getters/setters, you will have data-driven procedural programming where manipulation with that done in the straight imperative way. Get data - do something - set data.
In OOP encapsulation is an elephant if done in right way. You should encapsulate state and implementation details so that object has full control on that. Logic will be focused inside object and will not be spread all over the codebase. And yes - encapsulation is still essential in programming as the code will be more maintainable.
EDITS
After seeing the discussions going on I want to add several things:
- It doesn't matter how many of your attributes you expose through getters/setters and how carefully you doing that. Being more selective will not made your code OOP with encapsulation. Every attribute you expose will lead to some procedure working with that naked data in imperative procedural way. You will just spread your code less slowly with being more selective. That doesn't change the core.
- Yes, in boundaries within the system you get naked data from other systems or database. But this data is just another encapsulation point.
- Objects should be reliable. The whole idea of objects is being resposinble so that you don't need to give orders that are straight and imperative. Instead you asking object to do what he does well through the contract. You safely delegate acting part to the object. Object encapsulate state and implementation details.
So if we return to question why should we do this. Consider this simple example:
public class Document { private String title; public String getTitle() { return title; } } public class SomeDocumentServiceOrHandler { public void printDocument(Document document) { System.out.println("Title is " + document.getTitle()); } } Here we have Document exposing internal detail by getter and have external procedural code in printDocument function which works with that otside of the object. Why this is bad? Because now you just have C style code. Yes it is structured by what really the difference? You can structure C functions in different files and with names. And that so called layers doing exactly that. Service class is just a bunch of procedures that's works with data. That code is less maintanable and have many drawbacks.
public interface Printable { void print(); } public final class PrintableDocument implements Printable { private final String title; public PrintableDocument(String title) { this.title = title; } @Override public void print() { System.out.println("Title is " + title); } } Compare with this one. Now we have contract and implemantation details of that contract is hide inside of the object. Now you can truly test that class and that class is encapsulating some data. How it works with that data is an object concerns. In order to talk with object now you need to ask him to print itself. That's encapsulation and that is an object. You will gain the full power of dependency injection, mocking, testing, single responsibilities and a lot bunch of benefits with OOP.
Hope this helps.