Why we care
When modifying Java access, the general rule is to use only the minimum level of access that is necessary. Why? The idea is to encapsulate each piece of your system as much as possible. This way, you protect yourself and others from refactors that might have a ripple effect on other parts of the system. So, if you want to allow others to use your BuzzingBees method, but want to be able to modify BeautifulButterflies at your leisure, you can lock access to the butterflies down. You should be able to optimize your own code without breaking other code as much as possible. So, generally you want to start with private and go from there.
So how do we decide? In order of least private to most private:
Public, the simplest of the modifiers, will make the object most widely accessible. Everything in the module can see something public. It is accessible in all classes. If I was the queen of a kingdom, my castle would be big enough for everyone to see. Anyone could come up to the front gates and request entry to the castle via the bridge. They could even walk through the surrounding garden. But they wouldn’t be able to access the main hall or any of the contents of the castle without permission because these are not public.
Protected allows less access than public, making the member visible by classes throughout the same package OR any subclasses. This is package scope and child scope--potentially the most confusing level of access. Give protected access if you want to do some internal things that should not be exposed publicly, but still intend for the class to be inherited and potentially overridden by subclasses. If you want to change access from private to protected purely for unit testing, try to document that its functionality is not meant to be overwritten. If a lord or lady who carried the same family crest as me on their flag were to come to the gates of my castle, they would be granted entry immediately. They could come and go as they please in and out of the main hall.
With no modifier (default), a member will be accessible within all classes that are in the same package. This is package scope. Crest-carrying members of my family can be inside the castle, but only higher-ranking members, like the mother of the queen, who have been granted special privileges, may access the library or speak to the guards of the dungeon.
The private modifier restricts member access to only that specific class. This is also called class scope. It is a good starting place. To understand why, note that changing access from private to protected will not be a breaking change, but going the opposite way could be. Try to start here and add access when necessary. In our analogy, the castle is not completely open to my relatives. I would never allow my mother access to the treasure room, for example.
So, remember to drink lots of water, wash your face before going to bed, and use the minimum level of access necessary in your java code.
Modifier | Class | Package | Subclasses | World |
---|---|---|---|---|
public | ✅ | ✅ | ✅ | ✅ |
protected | ✅ | ✅ | ✅ | ❌ |
no modifier | ✅ | ✅ | ❌ | ❌ |
private | ✅ | ❌ | ❌ | ❌ |
Top comments (8)
In my opinion, making anything protected from private to make it testable is generally a bad practice. You shouldn’t test private parts of the class, just the public (or package private if it is meant to be used just internally) API (which still includes private methods). If its hard to test because of the logic in these private methods, then its a design issue and you might want to extract that part from the class.
One thing I'll add is that you should be able to test the private logic via the public interface anyways. IOW, if you can get complete coverage of your public interface and your private logic isn't tested, then you either don't really have full coverage or your private logic isn't accessible anyways (and get rid of it).
Well I would have agreed a few years ago but now I've been coding in many languages and it appears that this strategy isn't really useful in my opinion.
In Java if you want to keep your sanity then use interfaces as much as possible to define types. And since the interface is the minimal promise you make to the outside world, just set everything to public.
Also, only declare methods in interfaces (yeah the getters/setters debate)
And finally, everything in the same code base should be able to access "publicly" everything else from that same code base. It's safe because your IDE will tell you about any mistake you make. And it saves you mental load.
No, just please no. You really shouldn't expose everything. That's just nonsense. You should expose carefully and use the least access modifier possible in any case. If you develop a library, you shouldn't expose the whole of it for the client, because:
Also look at the top of your source files. How many import do you see? Not the whole codebase I guess. That's because when you use something then you'll start depending on it. And you don't want to depend on the whole codebase. Use private fields, private inner classes if needed. Don't let your own code to fool you or anyone else, be defensive.
How can the IDE tell me about mistakes in this case? When everything is public there are no access related mistakes.
Well private fields are private because you don't want to guarantee internal structure to outsiders so if you change it other apps don't get broken.
Here if you change something you're going to break the compilation so you're basically going to notice that you've broken your app/lib. Thus you are pretty safe.
While this makes sense, I still don't get your point.
If I understand you correctly, you suggest to make all fields and methods of a class public because encapsulation does not provide much value.
This means that every part of your codebase is potentially directly connected to any other part. How do you keep the design from turning into a Big Ball of Mud? You mention interfaces. But how do you make sure everybody uses them and does not access the classes directly?
This is such a fun analogy - looking forward to the medieval mental images every time I write a new class!