Why assigning a final field in a try-catch block within a static block is rejected?

135 views Asked by At

I'm trying to write following class:

public class Secteur {
    private final static int num_secteur;
    static{
            try {
                num_secteur = SecteurDAO.getCurrNumSecteur();
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            }

    }
}  

But I'm having following warning :

The blank final field num_secteur may not have been initialized

The SecteurDAO.getCurrNumSecteur() method accesses the database in order to get the integer that will be set to num_secteur field.
What is the problem with my code ?

2

There are 2 answers

2
Thomas On

The call to SecteurDAO.getCurrNumSecteur() might fail (throw an exception) and thus there's no value to assign to num_secteur. Hence it might not be initialized in case of an exception.

To fix that you might either want to initialize it with some special value (e.g. -1) or set that value in the catch-block.

Oh, and remove the final keyword, otherwise you'd get the error message "The final field num_secteur may already have been assigned". That's because you can only ever assign a value to a final field once and even if you know that assignment can't happen in case of an exception (because the exception will be thrown before) the compiler can't know that for sure and hence tells you that the variable might have been already assigned.

0
rgettman On

As as been explained, if there is an exception, the variable might not be assigned at the end of the static initializer.

You might think of assigning to the variable before the try block, or after the catch block, but that can lead to 2 assignments to the variable, so that's disallowed.

You might think of assigning an invalid value to the variable in the catch block, but that still can lead to 2 assignments to the variable.

The best way to assign this variable exactly once, and still keep num_secteur final, is to use a temporary variable and assign it to num_secteur in a finally block.

private final static int num_secteur;
static
{
    int test = -1;  // Invalid value.
    try {
        test = SecteurDAO.getCurrNumSecteur();
    } catch (ClassNotFoundException | SQLException e) {
        e.printStackTrace();
    } finally {
        // Only assigned here, exactly once.
        num_secteur = test;
    }
}