Question

Effective Java (Second Edition), Item 4, discusses using private constructors to enforce noninstantiability. Here's the code sample from the book:

public final class UtilityClass {
    private UtilityClass() {
        throw new AssertionError();
    }
}

However, AssertionError doesn't seem like the right thing to throw. Nothing is being "asserted", which is how the API defines the use of AssertionError.

Is there a different Throwable that's typically in this situation? Does one usually just throw a general Exception with a message? Or is it common to write a custom Exception for this?

It's pretty trivial, but more than anything I guess I'm just curious about it from a style and standards perspective.

Was it helpful?

Solution

There is an assertion: "I'm asserting that this constructor will never be called". So, indeed, AssertionError is correct here.

OTHER TIPS

I like including Bloch's comment:

// Suppress default constructor for noninstantiability

Or better yet putting it in the Error:

private UtilityClass()
{
    throw new AssertionError("Suppress default constructor for noninstantiability");
}

UnsupportedOperationException sounds like the best fit, though a checked exception would be even better, since it might warn someone erroneously instantiating the class at compile time.

What about IllegalAcessError ? :)

No no no, with all due respect to Josh Bloch, never throw an AssertionError unless it's from an assertion. If you want an AssertionError here, throw it with assert(false). Then someone reading the code can find it later.

Even better, define your own exception, say CantInstantiateUtilityClass. then you'll have code that says

try {
    // some stuff
} catch (CantInstantiateUtilityClass e) {
    // react
}

so that the reader of the catcher knows what happened.

Update

Every so often some damn fool wanders by here and downvotes this again, almost four years after the fact. So, let me just note that the standard still defines AssertionError as the result of a failed assertion, not as what some beginner thinks ought to be thrown in place of a well-defined informative exception. Sadly, good exception discipline is perhaps the least encouraged skill in Java programming.

When the code requires the inclusion of the JUnit as a dependency such as within the maven test scope <scope>test</scope>, then go straight to Assertion.fail() method and benefit from significant improvement in clarity.

public final class UtilityClass {
    private UtilityClass() {
        fail("The UtilityClass methods should be accessed statically");
    }
}

When outside the test scope, you could use something like the following, which would require a static import to use like above. import static pkg.Error.fail;

public class Error {
    private static final Logger LOG = LoggerFactory.getLogger(Error.class);
    public static void fail(final String message) {
        LOG.error(message);
        throw new AssertionError(message);
        // or use your preferred exception 
        // e.g InstantiationException
    }
}

Which the following usage.

public class UtilityClassTwo {
    private UtilityClassTwo() {
        Error.fail("The UtilityClass methods should be accessed statically");
    }
}

In its most idiomatic form, they all boil down to this:

public class UtilityClassThree {
    private UtilityClassThree() {
        assert false : "The UtilityClass methods should be accessed statically";
    }
}

One of the built in exceptions, UnsupportedOperationException can be thrown to indicate that 'the requested operation is not supported'.

 private Constructor() {
    throw new UnsupportedOperationException(
            "Do not instantiate this class, use statically.");
}

A broken assertion means that you've broken a contract specification of your code. So it's the right thing here.

However, as I assume you'll be privately instantiating an instance, it will also call the constructor and cause an error- unless you have another constructor?

You can create your own class extending Throwable, e.g.:

class NoninstantiabilityError extends Throwable

This has the following advantages:

  • The name indicates the problem
  • Because it directly extends Throwable it is unlikely that it will be caught by accident
  • Because it directly extends Throwable it is checked and calling the respective constructor by accident would require catching the exception

Usage example:

public final class UtilityClass {
    private UtilityClass() throws NoninstantiabilityError {
        throw new NoninstantiabilityError();
    }

    ...
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top