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

前端 未结 8 1258
青春惊慌失措
青春惊慌失措 2020-12-14 01:07

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

public fi         


        
相关标签:
8条回答
  • 2020-12-14 01:12

    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();
        }
    
        ...
    }
    
    0 讨论(0)
  • 2020-12-14 01:13

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

    0 讨论(0)
  • 2020-12-14 01:13

    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.");
    }
    
    0 讨论(0)
  • 2020-12-14 01:15

    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");
    }
    
    0 讨论(0)
  • 2020-12-14 01:23

    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?

    0 讨论(0)
  • 2020-12-14 01:24

    What about IllegalAcessError ? :)

    0 讨论(0)
提交回复
热议问题