MK.
MK.

Reputation: 34587

pattern for getting around final limitation of Java closure

I'm trying to write a very simple piece of code and can't figure out an elegant solution to do it:

int count = 0;
jdbcTemplate.query(readQuery, new RowCallbackHandler() {
         @Override
         public void processRow(ResultSet rs) throws SQLException {
            realProcessRow(rs);
            count++;
         }
      });

This obviously doesn't compile. The 2 solutions that I'm aware of both stink: I don't want to make count a class field because it's really a local variable that I just need for logging purposes. I don't want to make count an array because it is plain ugly.

This is just silly, there got to be a reasonable way to do it?

Upvotes: 0

Views: 167

Answers (3)

newacct
newacct

Reputation: 122489

You seem to already be aware of the solutions (they are different though); and you are probably aware of the reasons (it cannot capture local variables by reference because the variable might not exist by the time the closure is run, so it must capture by value (have multiple copies); it is bad to have the same variable refer to different copies in different scopes that each can be changed independently, so they cannot be changed).

If your closure does not need to share state back to the enclosing scope, then a field in the class is the right thing to do. I don't understand what your objection is. If the closure needs to be able to be called multiple times and it needs to increment each time, then it needs to maintain state in the object. A field (instance variable) properly expresses the storing of state in an object. The field can be initialized with the captured value from the outside scope.

If your closure needs to share state back to the enclosing scope (which is not a very common situation), then using a mutable structure (like an array) is the right thing to do, because it avoids the problem of the lifetime of the local variable.

Upvotes: 2

user949300
user949300

Reputation: 15729

I typically make count a class field but add a comment that it is only a field because it is used by an inner closure, Runnable etc...

Upvotes: 0

assylias
assylias

Reputation: 328735

A third possibility is to use a final-mutable-int-object, for example:

final AtomicInteger count = new AtomicInteger(0);
....
count.incrementAndGet();

Apache Commons also have a MutableInteger I believe, but I have not used it.

Upvotes: 5

Related Questions