Default access does not render the private access modifier redundant.
Language designers position on that is reflected in official tutorial - Controlling Access to Members of a Class and it's pretty clear (for your convenience, relevant statement in the quote made bold):
Tips on Choosing an Access Level:
If other programmers use your class, you want to ensure that errors from misuse cannot happen. Access levels can help you do this.
- Use the most restrictive access level that makes sense for a particular member. Use private unless you have a good reason not to.
- Avoid public fields except for constants. (Many of the examples in the tutorial use public fields. This may help to illustrate some points concisely, but is not recommended for production code.) Public fields tend to link you to a particular implementation and limit your flexibility in changing your code.
Your appeal to testability as justification for completely dropping private modifier is wrong, as evidenced eg by the answers in New to TDD. Should I avoid private methods now?
Of course you can have private methods, and of course you can test them.
Either there is some way to get the private method to run, in which case you can test it that way, or there is no way to get the private to run, in which case: why the heck are you trying to test it, just delete the damn thing...
Position of language designers on the purpose and usage of package level access is explained in another official tutorial, Creating and Using Packages and it has nothing in common with the idea of dropping private modifiers (for your convenience, relevant statement in the quote made bold):
You should bundle these classes and the interface in a package for several reasons, including the following:
- You and other programmers can easily determine that these types are related...
- You can allow types within the package to have unrestricted access to one another yet still restrict access for types outside the package...
<rant "I think I heard enough whining. Guess it's about time to say loud and clear...">
Private methods are beneficial to unit testing.
Note below assumes that you are familiar with code coverage. If not, take a time to learn, since it's quite useful to those interested in unit testing and in testing at all.
All right, so I've got that private method and unit tests, and coverage analysis telling me that there's a gap, my private method isn't covered by tests. Now...
What do I gain from keeping it private
Since method is private, the only way to proceed is to study the code to learn how it is used through non-private API. Typically, such a study reveals that reason for the gap is that particular usage scenario is missing in tests.
void nonPrivateMethod(boolean condition) {
if (condition) {
privateMethod();
}
// other code...
}
// unit tests don't invoke nonPrivateMethod(true)
// => privateMethod isn't covered.
For the sake of completeness, other (less frequent) reasons for such coverage gaps could be bugs in specification / design. I won't dive deep into these here, to keep things simple; suffice to say that if you weaken access limitation "just to make method testable", you'll miss a chance to learn that these bugs exist at all.
Fine, to fix the gap, I add a unit test for missing scenario, repeat coverage analysis and verify that gap is gone. What do I have now? I've got as new unit test for specific usage of non-private API.
New test ensures that expected behavior for this usage won't change without a notice since if it changes, test will fail.
An outside reader may look into this test and learn how it is supposed to use and behave (here, outside reader includes my future self, since I tend to forget the code a month or two after I'm done with it).
New test is tolerant to refactoring (do I refactor private methods? you bet!) Whatever I do to privateMethod
, I'll always want to test nonPrivateMethod(true)
. No matter what I do to privateMethod
, there will be no need to modify test because method isn't directly invoked.
Not bad? You bet.
What do I loose from weakening access limitation
Now imagine that instead of above, I simply weaken access limitation. I skip the study of the code that uses the method and proceed straight with test that invokes my exPrivateMethod
. Great? Not!
Do I gain a test for specific usage of non-private API mentioned above? No: there was no test for nonPrivateMethod(true)
before, and there is no such test now.
Do outside readers get a chance to better understand usage of the class? No. "- Hey what's the purpose of the method tested here? - Forget it, it's strictly for internal use. - Oops."
Is it tolerant to refactoring? No way: whatever I change in exPrivateMethod
, will likely break the test. Rename, merge into some other method, change arguments and test will just stop compiling. Headache? You bet!
Summing up, sticking with private method brings me a useful, reliable enhancement in unit tests. In contrast, weakening access limitations "for testability" only gives me an obscure, hard to understand piece of test code, which is additionally at permanent risk of being broken by any minor refactoring; frankly what I get looks suspiciously like technical debt.
</rant>