How to handle a static final field initializer that throws checked exception
Asked Answered
R

4

51

I am facing a use case where I would like to declare a static finalfield with an initializer statement that is declared to throw a checked exception. Typically, it'd look like this:

public static final ObjectName OBJECT_NAME = new ObjectName("foo:type=bar");

The issue I have here is that the ObjectName constructor may throw various checked exceptions, which I don't care about (because I'd know my name is valid, and it's allright if it miserably crashes in case it's not). The java compiler won't let me just ignore this (as it's a checked exception), and I would prefer not to resort to:

public static final ObjectName OBJECT_NAME;
static {
    try {
        OBJECT_NAME = new ObjectName("foo:type=bar");
    } catch (final Exception ex) {
        throw new RuntimeException("Failed to create ObjectName instance in static block.", ex);
    }
}

Because static blocks are really, really difficult to read. Does anyone have a suggestion on how to handle this case in a nice, clean way?

Reproduction answered 8/12, 2009 at 12:50 Comment(1)
My personal solution is to throw a CheckedExceptionsAreAPainInTheAssSometimesException, which is a runtime exception. The program will then just crash.Pursue
N
54

If you don't like static blocks (some people don't) then an alternative is to use a static method. IIRC, Josh Bloch recommended this (apparently not in Effective Java on quick inspection).

public static final ObjectName OBJECT_NAME = createObjectName("foo:type=bar");

private static ObjectName createObjectName(final String name) {
    try {
        return new ObjectName(name);
    } catch (final SomeException exc) {
        throw new Error(exc);
    }  
}

Or:

public static final ObjectName OBJECT_NAME = createObjectName();

private static ObjectName createObjectName() {
    try {
        return new ObjectName("foo:type=bar");
    } catch (final SomeException exc) {
        throw new Error(exc);
    }  
}

(Edited: Corrected second example to return from method instead of assign the static.)

Natalianatalie answered 8/12, 2009 at 13:20 Comment(5)
I didn't think about it, despite now that I read it I'm 100% certain I've used this approach a long time ago. I'll use this as I don't like static blocks and also like my code to be readable by beginners (You never know who'll maintain you code after yourself :)).Reproduction
gives me a compiler error of "must return a result of type ObjectName" -- would a simple solution be to have return null in the catch block? But then a little odd to debugMagavern
I think you are referring to Item 59: Avoid unnecessary use of checked exceptions (Effective Java, 2nd Edition). In that item, Bloch is advising the author of the code that throws an exception to consider if its clients 'can take some useful action once confronted with the exception'. That is different from this case, where the question isn't the legitimacy of the exception thrown, but how best to handle the exception. From looking at the documentation for java.lang.Error, I get the feeling throwing an error isn't the best thing to do here.Fitter
Errors should be used for 'abnormal conditions' that indicate 'serious problems' with the program. In the examples Bloch gives, AssertionErrors are only thrown in code that should never run, e.g. in the default section of a switch block, or within a private constructor of an un-instantiable class. IMHO, given the fact that the exceptional condition in this case is not improbable, throwing a RuntimeException is more appropriate than throwing an Error.Fitter
@Fitter This is from six years ago! I was referring to the Bloch advice (may have changed in the last decade) about creating static methods for construction instead of instance initialisers. Searching through 2nd Ed of Effective Java on the Kindle it doesn't actually appear to be in that book. / The intention of the thrown exception is to signal that the class is broken and it must die. That's an error. (Will get wrapped in java.lang.ExceptionInInitializerError.) Error is also much more readable than nonsense RuntimeException.Natalianatalie
S
18

Your code is perfectly valid. I don't find it difficult to read. Other ways would only make it more worse. They're only difficult to read for starters, because most of them are not familiar with that. Just follow the standard conventions with regard to ordering of the elements in the code. E.g. do not put static initializers halfway or at the whole bottom of the code and also do not have multiple of them spreading over the class. Just put one at top, after static declarations.

Stepheniestephens answered 8/12, 2009 at 12:54 Comment(2)
This is a very valid point (so I voted it up despite not accepting it), ant the GPP is also best stated. I won't use that method because as you say, this is only difficult to understand/read for beginners... And I can't ensure the people who'll maintain it after me are experienced :).Reproduction
I am not sure if I would prefer that. With refactoring it into a private static method you risk losing the oversight. Normal practice is that those kind of methods (utility methods) are placed at the whole bottom of the class. But OK, nowadays you have IDE's so that you can just click ahead.Stepheniestephens
M
5

static blocks aren't difficult to read. So I'd recommend that solution. However, you can wrap your object in another object, for example ObjectNameWrapper which shares an interface with your ObjectName, and whose constructor calls your ObjectName constructor, hiding all checked exceptions that occur. But again, I'd go for the static option.

Messinger answered 8/12, 2009 at 12:54 Comment(2)
Introducing another object seem obtuse.Natalianatalie
I certainly agree with you. Your static method suggestion is way better.Messinger
D
4

You can use a method annotated with Lombok's @SneakyThrows

public static final ObjectName OBJECT_NAME = createObjectName();

@SneakyThrows(SomeException.class)
private static ObjectName createObjectName() {
    return new ObjectName("foo:type=bar");
}

This annotation makes a checked exception behaves like an unchecked one.

Dominick answered 12/9, 2020 at 16:2 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.