16

I have a variable that is not supposed to change its value after it's been initialized, so I want to define it as a final variable.

the problem is that the variable has to be initialized inside a try block, so I get the following troubles:

I have the following code:

Connection conn = null;
try {
    conn = getConn(prefix);
    [...do some stuff with conn...]
} catch (Exception e) {
    throw new DbHelperException("error opening connection", e);
} finally {
    closeConnection(conn);
}

If I declare the variabale as final, without initializing it to null, I get a 'The local variable conn may not have been initialized' on the finally block. On the other hand, if I declare it final and initialize it to null, I get the error 'The final local variable conn cannot be assigned' in the try block.

EDIT: after lxx answer, I came with this version

try {
    final Connection conn = conn = getConn(prefix);
    try {
        return selectAll(conn, sql, params);
    } catch (Exception e) {
        throw new DbHelperException("error executing query", e);
    } finally {
        closeConnection(conn);  
    }
} catch (Exception e) {
    throw new DbHelperException("error opening connection", e);
}

So this should be the way to do it?

--

Lesson learned:

I think that the correct answer to the question is the one that lxx gave, but in this case I guess that the cons of declaring the variable final outweights it's benefits...

--

EDIT: found two questions on stack overflow about when to use final

When should one use final for method parameters and local variables?

Using "final" modifier whenever applicable in java

Community
  • 1
  • 1
opensas
  • 60,462
  • 79
  • 252
  • 386
  • How about appending `final Connection finalConn = conn;` to your code? – biziclop Feb 19 '12 at 15:48
  • Why do you need both `try`s? Why not just have a single try-catch in which you get the connection and use it to select all? – yshavit Feb 19 '12 at 16:05
  • I'd question why you think it's so important to declare this as final. It seems rather nannyish and naggy to me. If I were a user, and I called your method to get a connection, I can't see any reason why I'd want to muck that up by changing it. And if I did, I'd argue that the consequences ought to be on the user. – duffymo Feb 19 '12 at 16:21
  • Agree with duffymo. For a local variable in such a short block of code final is not necessary. – User Feb 19 '12 at 16:25
  • yshavit: the both tries is the way I've found -thanks to lxx- to keep the variable as final... – opensas Feb 19 '12 at 16:45
  • duffymo and lxx: I thought that marking variables as final, whenever possible, was a good practice with no downsides, now I realiza that in some cases it may needlessly complicate your code. In this case I doubt the compiler can optimize anything at all because of the final declaration, and on the other hand the nested try-catch add complexity to it... – opensas Feb 19 '12 at 16:48
  • @opensas `final` is extra text which is a downside. On a local variable, in my opinion, it is usually not justified although the idea is good. All variables should have defaulted to `final`. – Tom Hawtin - tackline Feb 19 '12 at 18:20
  • @opensas Marking local variables as final without a reason is bad practice. Only variables that are used in anonymous inner classes should be `final`, don't bother about the rest. – biziclop Feb 19 '12 at 19:07
  • @biziclop: `[citation needed]`! I don't think marking local variables as `final` is a bad practice. As the other comments in this thread point out, it might qualify as *dubious* practice (especially in a short method), but there's nothing specifically *bad* about it, IMO. – Daniel Pryden Feb 19 '12 at 23:37
  • @DanielPryden What's bad about it is that without a definite purpose it;s misleading. Furthermore, it's often used to "improve performance", and we know that premature optimisation is bad. Lastly, it can lead to convoluted constructs that you'd normally only see in association with closures. (Which, without the power of closures is a lose-lose situation.) – biziclop Feb 20 '12 at 00:42

4 Answers4

7

You could handle the Exceptions more accurately. If you get an Exception opening the connection, you don't have to close it in the finally block I guess. If you get an exception after that, in the try block, and handle the exception in a new nested try-catch block you don't need to define the variable outside. Something like:

    try {
        final Connection conn = getConn(prefix);
        try {
            //code using conn
        } catch (Exception e) {

        } finally {
            closeConnection(conn);
        }
    } catch (DbHelperException e) {
        throw new DbHelperException("error opening connection", e);
    }
User
  • 31,811
  • 40
  • 131
  • 232
  • Yes, I see what you mean, I assume that if there's an exception opening the connection, the connection couldn't be opened, so there's no need to close it. I came with another version of the code, thanks to your answer, check the question again... – opensas Feb 19 '12 at 16:03
  • @opensas If there's an exception in the `getConn()` call, whether the connection was in fact opened or not, `conn` will definitely be null, so you won't be able to close it anyway. – biziclop Feb 19 '12 at 19:04
  • This will be fine when outer try catch is necessary, but when i dont need outer try catch, what should i do ? – Kanagavelu Sugumar Mar 29 '18 at 17:51
2

How about this?

Connection temp = null;
try {
    temp = getConn(prefix);
} catch (Exception e) {
    throw new DbHelperException("error opening connection", e);
} finally {
    closeConnection(conn);
}
final Connection conn = temp;
Eng.Fouad
  • 115,165
  • 71
  • 313
  • 417
-2

Why do you want it final? If you want to pass it to an anonymous inner class, you could do:

Connection conn = null;
try {
    conn = getConn(prefix);
    final Connection finalConn = conn;
    // pass it to inner class here
} catch (Exception e) {
    throw new DbHelperException("error opening connection", e);
} finally {
    closeConnection(conn);
}

The only problem (and quite a big one) with this solution is that you close your connection as soon as you leave this block. So unless you declare and call your anon inner class straight away, this pattern isn't going to work.

Either way, I'd probably rephrase the whole thing if I were you, making prefix final instead and delegating connection handling to the anon inner class.

biziclop
  • 48,926
  • 12
  • 77
  • 104
  • oops! you are right, (BTW, you catched a nasty bug, thanks) - updated the question... – opensas Feb 19 '12 at 15:56
  • 2
    and I want to define it final, just to tell the compiler that the variable conn is not supposed to change it's value after being initialized... – opensas Feb 19 '12 at 15:58
-3

Can you try assigning it in both the catch and finally blocks? Like so:

Connection connTemp = null;
final Connection conn;
try {
    connTemp = getConn(prefix);
} catch (Exception e) {
    throw new DbHelperException("error opening connection", e);
} finally {
    closeConnection(conn);
}
conn = connTemp;
AlexanderZ
  • 521
  • 2
  • 6