Rob Hruska
Rob Hruska

Reputation: 120456

What is the preferred Throwable to use in a private utility class constructor?

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.

Upvotes: 36

Views: 13133

Answers (8)

Charlie Martin
Charlie Martin

Reputation: 112414

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.


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.

Upvotes: 2

Marcono1234
Marcono1234

Reputation: 6934

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();
    }

    ...
}

Upvotes: 0

Martin Spamer
Martin Spamer

Reputation: 5585

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.");
}

Upvotes: 2

Craig P. Motlin
Craig P. Motlin

Reputation: 26758

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");
}

Upvotes: 12

Michael Borgwardt
Michael Borgwardt

Reputation: 346526

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.

Upvotes: 7

OscarRyz
OscarRyz

Reputation: 199333

What about IllegalAcessError ? :)

Upvotes: 3

Steve B.
Steve B.

Reputation: 57333

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?

Upvotes: 0

C. K. Young
C. K. Young

Reputation: 223183

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

Upvotes: 43

Related Questions