Monday, June 23, 2008

Java Private Constructor Cleverness?



Hello there.






Uh... hi.




Are you ready to talk about Java?






For a little while at least.




I'll try not to bore you then. Let's get right to it...


Does your project have a StringUtils class?






Of course. Everyone has a StringUtils. Ours is just a bunch of methods that operate on Strings.




I thought so, it's pretty common.


Does its lack of OO purity bother you?






Oh geez. Go preach to someone else.




But doesn't it make extending the system harder? Doesn't it make unit testing hard?






My StringUtils has never been an issue.




Maybe StringUtils isn't the best example.


Does your project have a StateMachineUtils?






That class sounds a little suspect.




Indeed it does.


Can you imagine why it might be a poor idea?






Hmm. Tight coupling? Static dependencies?




Sure. Static methods in Java create a compile-time dependency on that specific method and class. As your system grows, you can't swap out the utility class with a different one in order to change the behavior of an object. A more immediate concern is that you can't swap out the utility class during testing in order to isolate your class under test. Every test becomes an integration test, retesting all the dependencies.






Still, my StringUtils has never been an issue. Sure it's procedural, statically bound code, but as long as you don't abuse it things should be alright.




Exactly. If your import statements are filled with java.lang references, then don't worry. If they are filled with java.sql or java.awt then think twice.




The Law of Utility Classes


Be wary of the dependencies in utility classes to avoid abusing them.





Is that all?




No. What I really wanted to talk about was private constructors.


  class StringUtils {

    //never instantiate a utility class

    private StringUtils() {}

  }






Ah yes, I've seen this before.


It makes it impossible to instantiate an object of type StringUtils. Seems prudent.




Yup. It's been a Java best practice since the days of Effective Java 1st Edition*.


If your class is not meant to be instantiated then don't allow people to do it. Without the private constructor, Java will create a default one for you that is public. The private constructor will make it impossible subclass or instantiate the utility class. The item is called "Enforce noninstantiability with private constructor".


* Thank you J. Bloch (1967 - )


The Second Law of Utility Classes


Provide a private constructor to enforce noninstantiability.





Sure. No arguments here.




But you can still instantiate the object, can't you?






You can do anything with reflection, right?




Sure, but there is a simpler way. How about creating an instance from within StringUtils itself. Any method within StringUtils is still free to reference the private constructor.


Do you know how to prevent this?






I suppose you could make the private constructor throw an exception.




Right.


  class StringUtils {

    //never instantiate a utility class

    private StringUtils() {

        throw new AssertionError();

    }

  }






What good is this?




Now there is no way to create an instance, even if a programmer inside your class decides that it should be done. If there is no sense in having instances then make it impossible to do so.


It is the ultimate safety. If something should not be done, then prohibit it.






Can't I still create an instance with cglib, using libraries like EasyMock?




Yes. This isn't perfect, but it is safer.




The Third Law of Utility Classes?


Enforce noninstantiability with private constructor that throw exceptions.





Is this really a solution to a problem?


Is your problem really maintenance programmers modifying classes when they don't have enough understanding to know when it isn't appropriate to instantiate a class?




Well, no. I don't have that problem.


We've had our share of poor developers come through our doors over the years, but this particular issue never arose.






What's the impact if someone did instantiate millions of these objects?


Is it any different than if a naive programmer constructed millions of any non-utility objects.




I guess not. Nothing that a profiling session wouldn't reveal, at any rate.






It sounds like this third law is optional. There's not a large benefit to following it.


Is this why the law contains a question mark?




I suppose it is. The question mark was my way of saying, "Maybe this law isn't always a maxim."


So the third law is optional, but the first two are certainly worth adhering too.






I'm not sure the second law is all that different from the third.


Both guard against a programmer doing something nonsensical but harmless.




Are you saying it is alright to leave out the private constructor on a utility class?


That the second law should contain a question mark also?






It does seem like extra work to prevent the possibility of a harmless and naive mistake on someone else's part.


I'd say it comes down to a style and cultural issue.




Cultural issue? How is safety a cultural issue?






Do you know the difference between a Directing Attitude and an Enabling Attitude?




I think I've heard the terms before.






A directing attitude attempts to prevent programmers from doing the wrong thing, limiting what they can do in order to limit their mistakes.


An enabling attitude attempts to give programmers the freedom to do whatever they need to do. Designs should make things easy to use well but not prevent mistakes.*


Thank you M. Fowler (1962 - )




I would say mainstream Java favors the directing attitude.






Perhaps.


But it would be OK for an enabling attitude to be taken, and to stop writing private constructors just to prevent mistakes.




I see how this would be acceptable in some workplaces. It's not the typical Java way, but could be done.


So neither the Second Law nor the Third Law are laws at all, but simply preferences. At least we have created one Law out of all this, the First Law.






Are you sure?




Quite. Utility classes have their place, but overuse makes the system difficult to extend.


Composition, small classes, and OO make software more malleable, and utility classes typically subvert this.






A lot of languages don't have objects.

How do they get by?




We're talking about Java here, so there's no point in asking that question.


The First Law should stand as a law.






OK. But don't forget, there are a lot of other languages out there too, even some that run on the JVM.






Yeah, yeah. Polyglot whatever.






I think we're both tired. Are we done here?




Yeah, we're done.


Now go make yourself some cookies, you deserve it.


12 comments:

Alex Miller said...

I dig the style. Makes me want to go read Hofstadter again. :) I was waiting for the Tortoise to show up.

I also like a practical approach that takes the attitude that your co-workers aren't idiots. (Unless of course they are, in which case you're screwed anyway.)

Ricky Clarkson said...

What is the smallest/simplest static method that needs to be abstracted into an interface so that multiple implementations are possible? Math.abs (remember there is also StrictMath.abs)? The identity function? I'll use [] instead of chevrons for generics:

public static [T] T identity(T t) {
return t; }

I'd say you only need to do that indirection when you actually need to use multiple implementations.

Casper Bang said...

"....you can't swap out the utility class during testing in order to isolate your class under test..."

Is this really an issue though? If we are truly talking about a utility class (DateUtils, StingUtils etc.) then surely there is no state involved, each and every method is idempotent and orthogonal to one another.

And really, what is the alternative? The fact is that java.lang.String is not equipped with every conceivable method.

Singletons and factory methods exhibit problems though but if you use the service provider pattern these are actually not too hard to swap out through class path dependency injection.

"...even if a programmer inside your class decides that it should be done..."

You can always boil things down to a HR issue. No language construct will shield you from this - even if I do feel we are in need of some better abstractions in Java, particular when dealing with resources.

Anonymous said...

you forgot that util classes should be final(you cant mock final classes). the real problem here is that people dont write tests for util classes.

Rubén Barroso said...

"...util classes should be final..." A private constructor already prevents a class from being extended.

Brian Oxley said...

Hofstadter is nice, of course. But what this reminds me of most is The Little Lisper. :)

Hamlet D'Arcy said...

Yes, it is a blatant Little Lisper rip-off.

I think both voices have good points, and are equally valid on their own. I think we're drawn towards wanting to synthesize two opinions into a "correct" middle-way, and assuming that either extreme end of the spectrum is necessarily wrong. But in this case there is no need for a middle way. There are a lot of people who will see the "throw Assert..." idiom and dogmatically apply it everywhere. And that's fine with me (so long as they use an IDE template). And there are some people who don't bother putting private constructors in, and I'm OK with that too. The only extreme I would reject is that there is no place for utility classes within Java.

Perhaps this is just a variation of the whitespace debate, in which there is no correct answer yet people are will to argue ad nauseum about it. :)

Moandji Ezana said...

Coincidentally, I just posted about the same topic, giving an example of replacing a utility class by a subclass.

Is it super-important? Probably not. I see it as a subset of "Keep data and behaviour together". And it looks nicer.

Robert Fischer said...

It reminds me most of Stephen Colbert's "Formidable Opponent" segments.

Anyway, there is a lot of places when you want -- nay, need -- a constructor, even for a utility class. Spring is a classic example: if I want to specify one of your utility class methods via Spring configuration, I'm going to need to be able to instantiate the class to create it as a bean. Also, if I'm not keen on using static imports, it's easy to do a private static final StringUtils su = new StringUtils(): the extra space burnt for the object won't be noticed.

This is one of the cases where efforts to prevent "bad behavior" are really overstepping their bounds.

alexbl said...

There are issues with private constructors (and private members in general) that make code reuse difficult, if not impossible. Recently I've been working on an implementation of a wrapper around org.w3c.dom.* and javax.parsers.DocumentBuilder* as host objects for Rhino. We had a need to extend the parser we were using (xerces) to annotate DOM nodes with line numbers, and so I subclassed Xerces DOMParser and extended it as needed (they have an example of doing this actually), but then when I went to put together a custom DocumentBuilder class i learned that I couldn't actually subclass Xerce's DocumentBuilderImpl because the member that held the dom parser was private, and accessed by member name, and so the only solution was to break out of doing it the JAXP way and call DOMParser directly, or copying all the code from DocumentBuilderImpl to change 1 or 2 lines. I opted for the first, which makes it a lot harder for people to swap out the DOM parser with another one.

Unknown said...

Hi

i like the way its presented in the form of dialog/discussion ....very intresting ....and it drives the reader till the end ......its nice .....good job !!!

木須炒餅Jerry said...
This comment has been removed by a blog administrator.