0

I have a class looks like this

class Some {

    private enum Inner {
    }
}

And I'm trying to find the Inner class in a initialization block of my test class.

class SomeTest {

    private static final Class<?> INNER_CLASS;

    {
        for (final Class<?> declaredClass: Some.class.getDeclaredClasses()) {
            if (declaredClass.getSimpleName().equals("Inner")) {
                INNER_CLASS = declaredClass;
                // Variable `INNER_CLASS` might be assigned in loop
                // break? return?
            }
        }
        throw new ExceptionInitializerError("failed to find Inner.class");
    }
}

The compiler doesn't like this and I couldn't find any better way.

How can I solve this? Is there any good pattern for this?

Jin Kwon
  • 20,295
  • 14
  • 115
  • 184
  • 1
    What does the compiler not like about this? I don't see a return statement, which means your `ExceptionInitializerError` will always be thrown. – Mark Jan 29 '19 at 07:53
  • Shouldn't it be a static initializer block? – M.F Jan 29 '19 at 07:54

4 Answers4

3

static and instance initialization block cannot throw checked exceptions as there is no way to declare that those blocks throws these execeptions. Change ExceptionInitializerError to RuntimeException (or any subclass) and wrap your code in try-catch

Besides here, you are not returning nor breaking thus you always throw exception.

As for "breaking out" well simply yo dont. You have to write that block as it would be body of void method but with the restriction that you cannot use return anywhere.

Antoniossss
  • 31,590
  • 6
  • 57
  • 99
2

There are a few problems with your code:

  1. You have the exception name incorrect. The exception you are trying to throw is called ExceptionInInitializerError not ExceptionInitializerError. That is one reason why it won't compile.

  2. Never1 throw Error or subclasses of Error.

  3. If you need to throw an unchecked exception, throw RuntimeException. Or better still, pick something more specific or define and use your own custom (unchecked) exception class.

  4. This should (probably) be a static initializer block, not a plain (instance) initializer. You want this code to be executed once ... not every time a SomeTest instance is created.

  5. Bailing out of a static initializer block is something you want to avoid. It basically leaves you with a dead application ... because the enclosing class and any classes that depend on it become uninitializable.


Having said that, the following might be a more appropriate structure:

 static {
     BlahType tmp = null;
     label: {
         for (...) {
             if (...) {
                 tmp = ...;
                 break label;
             }
         }
         throw new SomeException(...);
     }
     FINAL_VAR = tmp;
}

Note that we need to do the final assignment to FINAL_VAR in a way that ensures that it is definitely assigned. (My guess is that is a second reason you were getting compilation errors.)

And a more natural way to write the above would be:

static {
     BlahType tmp = null;
     for (...) {
         if (...) {
             tmp = ...;
             break;
         }
     }
     if (tmp == null) {
         throw new SomeException(...);
     }
     FINAL_VAR = tmp;
}

1 - Maybe a bit too strong. I would say that throwing AssertionError is OK ... assuming that you intend for it never be caught / recovered from. In this case, recovery is moot anyway.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
0

There are couple of issues:

  1. The exception is always thrown
  2. You are assigning to a final variable in a loop
  3. The initialization block is not static and assigning to a static final variable

Check this out:

class SomeTest {

    private static final Class<?> INNER_CLASS;

    static {
        Class<?> foundClass = null;
        for (final Class<?> declaredClass : Some.class.getDeclaredClasses()) {
            if (declaredClass.getSimpleName().equals("Inner")) {
                foundClass = declaredClass;
                // Variable `INNER_CLASS` might be assigned in loop
                // break? return?
            }
        }
        INNER_CLASS = foundClass;
        // throw new Exception("failed to find Inner.class");
    }
}
Dakshinamurthy Karra
  • 5,353
  • 1
  • 17
  • 28
0

Use intermediate variable before final assignment.

class SomeTest {

    private static final Class<?> INNER_CLASS;
    static {
        Class<?> innerClass = null;
        for (final Class<?> declaredClass: Some.class.getDeclaredClasses()) {
            if (declaredClass.getSimpleName().equals("Inner")) {
                innerClass = declaredClass;
            }
        }
        if (innerClass == null) {
            throw new ExceptionInitializerError("failed to find Inner.class");
        }
        INNER_CLASS = innerClass;
    }
}
Alex
  • 7,460
  • 2
  • 40
  • 51