Problems with local variable scope. How to solve it?
You have a scope problem indeed, because statement
is a local method variable defined here:
protected void createContents() {
...
Statement statement = null; // local variable
...
btnInsert.addMouseListener(new MouseAdapter() { // anonymous inner class
@Override
public void mouseDown(MouseEvent e) {
...
try {
statement.executeUpdate(query); // local variable out of scope here
} catch (SQLException e1) {
e1.printStackTrace();
}
...
});
}
When you try to access this variable inside mouseDown()
method you are trying to access a local variable from within an anonymous inner class and the scope is not enough. So it definitely must be final
(which given your code is not possible) or declared as a class member so the inner class can access this statement
variable.
Sources:
- Anonymous Classes
- How are Anonymous (inner) classes used in Java?
How to solve it?
You could...
Make statement
a class member instead of a local variable:
public class A1 { // Note Java Code Convention, also class name should be meaningful
private Statement statement;
...
}
You could...
Define another final variable and use this one instead, as suggested by @HotLicks:
protected void createContents() {
...
Statement statement = null;
try {
statement = connect.createStatement();
final Statement innerStatement = statement;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
...
}
But you should...
Reconsider your approach. If statement
variable won't be used until btnInsert
button is pressed then it doesn't make sense to create a connection before this actually happens. You could use all local variables like this:
btnInsert.addMouseListener(new MouseAdapter() {
@Override
public void mouseDown(MouseEvent e) {
try {
Class.forName("com.mysql.jdbc.Driver");
try (Connection connect = DriverManager.getConnection(...);
Statement statement = connect.createStatement()) {
// execute the statement here
} catch (SQLException ex) {
ex.printStackTrace();
}
} catch (ClassNotFoundException ex) {
e.printStackTrace();
}
});
Firstly, we just CAN'T make the variable final as its state may be changing during the run of the program and our decisions within the inner class override may depend on its current state.
Secondly, good object-oriented programming practice suggests using only variables/constants that are vital to the class definition as class members. This means that if the variable we are referencing within the anonymous inner class override is just a utility variable, then it should not be listed amongst the class members.
But – as of Java 8 – we have a third option, described here :
https://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html
Starting in Java SE 8, if you declare the local class in a method, it can access the method's parameters.
So now we can simply put the code containing the new inner class & its method override into a private method whose parameters include the variable we call from inside the override. This static method is then called after the btnInsert declaration statement :-
. . . .
. . . .
Statement statement = null;
. . . .
. . . .
Button btnInsert = new Button(shell, SWT.NONE);
addMouseListener(Button btnInsert, Statement statement); // Call new private method
. . .
. . .
. . .
private static void addMouseListener(Button btn, Statement st) // New private method giving access to statement
{
btn.addMouseListener(new MouseAdapter()
{
@Override
public void mouseDown(MouseEvent e)
{
String name = text.getText();
String from = text_1.getText();
String to = text_2.getText();
String price = text_3.getText();
String query = "INSERT INTO booking (name, fromst, tost,price) VALUES ('"+name+"', '"+from+"', '"+to+"', '"+price+"')";
try
{
st.executeUpdate(query);
}
catch (SQLException e1)
{
e1.printStackTrace(); // TODO Auto-generated catch block
}
}
});
return;
}
. . . .
. . . .
. . . .