25

I'm asking this question because I believe they did it for a very good reason and that most people do not use it properly, well from my experience in industry so far anyway. But if my theory is true then I'm not sure why they included the private access modifier...?

I believe that if default access is properly used it provides enhanced testability whilst maintaining encapsulation. And it also renders the private access modifier redundant.

The default access modifier can be used to provide the same affect by using a unique package for methods that need to be hidden from the rest of the world, and it does this without compromising testability, as packages in a test folder, with the same are able to access all the default methods declared in a source folder.

I believe this is why Java uses package access as 'default'. But I'm not sure why they also included private access, I'm sure there is a valid use case...

24

I guess they had a good idea of what an average programmer would do. And by average programmer I mean one who is not really good at programming, but gets the job anyway because there are not enough good ones and they are expensive.

If they made "public" access the default one, most programmers would never bother to use anything else. The result would be a lot of spaghetti code everywhere. (Because if you are technically allowed to call anything from anywhere, why ever bother to encapsulate some logic within a method?)

Making "private" the default access would only be slightly better. Most beginning programmers would simply invent (and share on their blogs) a rule of thumb that "you need to write 'public' everywhere", and then they would complain why Java is so bad that it forces them to write "public" everywhere. And they would also produce a lot of spaghetti code.

The package access is something that allows programmers to use their sloppy programming techniques while writing code within one package, but then they have to reconsider it when making more packages. It is a compromise between good business practices and the ugly reality. Like: write some spaghetti code, if you insist, but please leave the ugly mess within the package; at least create some nicer interfaces among the packages.

Probably there are other reasons, too, but I wouldn't underestimate this one.

14

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.

  1. New test ensures that expected behavior for this usage won't change without a notice since if it changes, test will fail.

  2. 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).

  3. 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!

  1. 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.

  2. 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."

  3. 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>

  • 7
    I've never found that argument for testing private methods compelling. You refactor code into methods all the time for reasons that have nothing to do with the public API of a class, and it's a very nice thing to be able to test those methods independently, without involving any other code. That is the reason you refactored, right? To get a piece of independent functionality. That functionality should be testable independently as well. – Robert Harvey Dec 12 '13 at 16:47
  • @RobertHarvey answer expanded with a rant addressing this. "Private methods are beneficial to unit testing..." – gnat Dec 13 '13 at 7:54
  • I see what you're saying about private methods and code coverage, but I wasn't really advocating making those methods public so that you can test them. I was advocating having a way to test them independently even though they are private. You can still have your public tests that touch the private method, if you want to. And I can have my private tests. – Robert Harvey Dec 13 '13 at 16:06
  • @RobertHarvey I see. Guess it boils down to coding style. At the amount of private methods I typically produce, and at the rate I refactor these, having tests for them is simply a luxury I can't afford. Non-private API is another matter, I tend to be quite reluctant and slow at modifying it – gnat Dec 13 '13 at 16:14
  • Perhaps you're better at writing methods that work the first time than I am. For me, I need to test the method to make sure that it works first before I can move on, and having to test it indirectly by firing off a series of other methods would be clumsy and awkward. – Robert Harvey Dec 13 '13 at 16:16
9

The likeliest reason is: it has to do with history. Java's ancestor, Oak, only had three access levels: private, protected, public.

Except that private in Oak was the equivalent of package private in Java. You can read section 4.10 of Oak's Language Specification (emphasis mine):

By default all variables and methods in a class (including constructors) are private. Private variables and methods can be accessed only by methods declared in the class, and not by its subclasses or any other classes (except for classes in the same package).

So to your point, the private access, as known in Java, was not there originally. But when you have more than a few classes in a package, not having private as we know it now would lead to a nightmare of name collision (for example, java.until.concurrent has close to 60 classes), which is probably why they introduced it.

However the default package access (originally called private) semantics were not changed between Oak and Java.

5

I believe that if default access is properly used it provides enhanced testability whilst maintaining encapsulation. And it also renders the private access modifier redundant.

There are situations where one would want two separate classes that are more tightly bound than exposing everything with public. This has similar ideas of 'friends' in C++ where another class that is declared as a 'friend' of another can access their private members.

If you look into the innards of classes such as BigInteger you will find a number of package default protection on fields and methods (everything that is blue triangle in the list). This allows other classes in the java.math package to have more optimal access to their innards for specific operations (you can find these methods called in BigDecimal - BigDecimal is backed by a BigInteger and saves reimplementing BigInteger again. That these are package level isn't an issue for protection because java.math is a sealed package and no other classes can be added to it.

On the other hand, there are many things that are indeed private, as they should be. Most packages aren't sealed. Without private, your co-worker could put another class in that package and access the (no longer) private field and break encapsulation.

Of note, unit testing wasn't something that was thought of back when the protection scopes were being constructed. JUnit (the XUnit testing framework for Java) wasn't conceived of until 1997 (one telling of the story of that can be read at http://www.martinfowler.com/bliki/Xunit.html ). The Alpha and Beta versions of the JDK were in 1995 and JDK 1.0 was in 1996, though the protection levels didn't really get nailed down until JDK 1.0.2 (prior to that you could have a private protected protection level).

Some would argue that the default shouldn't be package level, but private. Others argue that there shouldn't be a default protection but everything should be explicitly stated - some followers of this will write code such as:

public class Foo {
    /* package */ int bar = 42;
    ...
}

Note the comment there.

The real reason why the package level protection is the default is likely lost to the design notes of Java (I've been digging and can't find any why articles, lots of people explaining the difference, but none saying "this is the reason").

So I'll take a guess. And that's all it is - a guess.

First off, people were still trying to figure out language design. Languages since then have learned from Java's mistakes and successes. This could be listed as a mistake not to have something that needs to be defined for all fields.

  • The designers saw an occasional need for a 'friend' relationship of C++.
  • The designers wanted explicit statements for public, and private as these have the biggest impacts on access.

Thus, private isn't default and well, everything else fell into place. The default scope was left as default. It may have been the first scope that was created and in the interest of rigorous backwards compatibility with older code, was left that way.

As I said, these are all a guess.

  • Ah if only the friend feature could be applied to members on an indiviudal basis, so you could say void someFunction() can only been seen by class X... that would really tighten up encapsulation! – newlogic Dec 5 '13 at 10:31
  • Oh wait you can do this in C++, we need this in Java! – newlogic Dec 5 '13 at 10:32
  • 2
    @user1037729 it makes for a tighter coupling between the two classes - the class with the method now needs to know of the other classes that are its friends. This tends to go against the design philosophy that Java provides. The set of problems that is solvable with friends but not package level protection is not that large. – user40980 Dec 5 '13 at 15:11
2

Encapsulation is a way of saying "you don't have to think about this".

                 Access Levels
Modifier    Class   Package  Subclass   World
public        Y        Y        Y        Y
protected     Y        Y        Y        N
no modifier   Y        Y        N        N
private       Y        N        N        N

Putting these into nontechnical terms.

  1. Public: everyone has to think about it.
  2. Protected: default and subclasses have to know about it.
  3. Default, if you're working on the package, you'll know about it (it's right there in front of your eyes) might as well let you take advatage of it.
  4. Private, you only need to know about this if you are working on this class.
0

I don't think they focused on testing, simply because testing wasn't very common back then.

What i do think they wanted to achieve was encapsulation on the package level. A class can as you know have internal methods and fields and only expose some of it through public members. In the same way a package can have internal classes, methods and fields, and only expose some of it. If you think this way, a package has an internal implementation in a set of classes, methods and fields, along with a public interface in another (possibly partially overlapping) set of classes, methods and fields.

The most experienced coders I know think this way. They take encapsulation and apply it to an abstraction level higher than the class: a package, or a component if you like. Seems reasonable to me that the designers of Java were already this mature in their designs, considering how well Java still holds up.

  • You are right that automated testing wasn't very common back there. But it's an immature design. – Tom Hawtin - tackline Dec 16 '13 at 22:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.