I'm receiving the error "local variable box is accessed from within inner class; needs to be declared final". That seems alright, but I don't really think it's the best solution, so I was hoping maybe someone else can help me out. Here is my code:
public void showPublisherBox(JComboBox box) {
if (publisherBox == null) {
publisherBox = new AddPublisherForm();
publisherBox.setLocationRelativeTo(this);
}
publisherBox.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{
this.populatePublishers(box);
}
private void populatePublishers(JComboBox box){
box.setModel(db.getPublishers());
}
});
publisherBox.setVisible(true);
}
Publisher form is just a new JFrame that opens up and takes in some information, and when it's closed I want the JComboBox to be repopulated via setting the model from my db.getPublishers() method.
So is there a better way to do what I'm doing here, or am I going to have to declare something as final?
Thanks
Since you're not modifying box
in the outer code, using final
is exactly the correct way to solve this problem. It's a promise to yourself (and to the compiler) that the value of box
won't change in the enclosing scope. The compiler will tell you if you break that promise.
There is no compile time or runtime cost to using final
.
When an anonymous inner class (such as your WindowAdapter
) refers to variables in enclosing scopes (like 'box'), Java requires that they be declared final
.
One way to avoid having to declare box
as final
would be to make your WindowAdapter
a named class, that accepts the box
as a constructor parameter:
public void showPublisherBox(JComboBox box) {
if (publisherBox == null) {
publisherBox = new AddPublisherForm();
publisherBox.setLocationRelativeTo(this);
}
publisherBox.addWindowListener(new MyWindowClosingHandler(box, db));
publisherBox.setVisible(true);
}
// ...
class MyWindowClosingHandler extends WindowAdapter {
private JComboBox box;
MyWindowClosingHandler(JComboBox box, DB db) {
this.box = box;
this.db = db;
}
public void windowClosing(WindowEvent we) {
populatePublishers();
}
private void populatePublishers(){
box.setModel(db.getPublishers());
}
});
}
Nope. In this case, declare as final. The reference doesn't change anyway.
Local variables used by local classes must be declared as final. In this case, the variable is a method parameter, which you don't assign to anyway, so I see no reason why not to declare it as final.
Needless to say, this declaration has no effect on the caller of the method whatsoever. It only states that the local copy of the reference is not modified by the body of the method.
You should type "Final" every single time you declare a variable--I have no idea why Java didn't make final the default and require a "Variable" keyword or something instead. I'm just saying most variables should be final unless proven otherwise.
That said, you can always make a full class instead of an anonymous inner class and pass the variable into the constructor--that would be the "Correct" way to do it. Anonymous inner classes are a bad habit anyway--they discourage code reuse (The inner class cannot be reused as a listener in another place, whereas if it were a full class it would be easily reused--I've used this technique when refactoring to eliminate huge piles of redundant code.