Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems with local variable scope. How to solve it?

Tags:

java

scope

I'm getting the following error when trying to execute statemet.executeUpdate() in my code:

Local variable statement defined in an enclosing scope must be final or effectively final. 

This is my code so far:

import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement;.  import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text;  public class a1 {      protected Shell shell;     private Text text;     private Text text_1;     private Text text_2;     private Text text_3;      /**      * Launch the application.      * @param args      */     public static void main(String[] args) {         try {             a1 window = new a1();             window.open();         } catch (Exception e) {             e.printStackTrace();         }     }      /**      * Open the window.      */     public void open() {         Display display = Display.getDefault();         createContents();         shell.open();         shell.layout();         while (!shell.isDisposed()) {             if (!display.readAndDispatch()) {                 display.sleep();             }         }     }      /**      * Create contents of the window.      */     protected void createContents() {          Connection connect = null;          ResultSet resultSet = null;          try {             Class.forName("com.mysql.jdbc.Driver");         } catch (ClassNotFoundException e) {             // TODO Auto-generated catch block             e.printStackTrace();         }         try {             connect = DriverManager.getConnection("jdbc:mysql://localhost/railwaydb", "root", "");         } catch (SQLException e) {             // TODO Auto-generated catch block             e.printStackTrace();         }          Statement statement = null;         // statements allow to issue SQL queries to the database         try {             statement = connect.createStatement();         } catch (SQLException e) {             // TODO Auto-generated catch block             e.printStackTrace();         }          shell = new Shell();         shell.setSize(450, 300);         shell.setText("SWT Application");          Label lblName = new Label(shell, SWT.NONE);         lblName.setBounds(10, 43, 47, 15);         lblName.setText("Name");          Label lblFrom = new Label(shell, SWT.NONE);         lblFrom.setBounds(10, 74, 55, 15);         lblFrom.setText("From");          Label lblTo = new Label(shell, SWT.NONE);         lblTo.setBounds(10, 105, 55, 15);         lblTo.setText("To");          Label lblPrice = new Label(shell, SWT.NONE);         lblPrice.setBounds(10, 137, 55, 15);         lblPrice.setText("Price");          text = new Text(shell, SWT.BORDER);         text.setBounds(64, 43, 76, 21);          text_1 = new Text(shell, SWT.BORDER);         text_1.setBounds(64, 74, 76, 21);          text_2 = new Text(shell, SWT.BORDER);         text_2.setBounds(64, 105, 76, 21);          text_3 = new Text(shell, SWT.BORDER);         text_3.setBounds(64, 137, 76, 21);          Label lblRailwayDatabase = new Label(shell, SWT.NONE);         lblRailwayDatabase.setBounds(174, 10, 97, 15);         lblRailwayDatabase.setText("Railway Database");          Label lblCreateView = new Label(shell, SWT.NONE);         lblCreateView.setBounds(189, 43, 76, 15);         lblCreateView.setText("Create View");          Button btnName = new Button(shell, SWT.CHECK);         btnName.setBounds(189, 73, 93, 16);         btnName.setText("Name");          Button btnFrom = new Button(shell, SWT.CHECK);         btnFrom.setBounds(189, 105, 93, 16);         btnFrom.setText("From");          Button btnTo = new Button(shell, SWT.CHECK);         btnTo.setBounds(189, 137, 93, 16);         btnTo.setText("To");          Button btnPrice = new Button(shell, SWT.CHECK);         btnPrice.setBounds(189, 171, 93, 16);         btnPrice.setText("Price");          Button btnInsert = new Button(shell, SWT.NONE);         btnInsert.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 {                     statement.executeUpdate(query);                 } catch (SQLException e1) {                     // TODO Auto-generated catch block                     e1.printStackTrace();                 }             }         });         btnInsert.setBounds(10, 171, 75, 25);         btnInsert.setText("Insert");          Button btnView = new Button(shell, SWT.NONE);         btnView.setBounds(307, 74, 75, 25);         btnView.setText("View");          Button btnIndex = new Button(shell, SWT.NONE);         btnIndex.setBounds(307, 127, 75, 25);         btnIndex.setText("Index");      } } 

I also tried to set statement final but the declaration gives me another error.

like image 746
Amit Chahar Avatar asked Sep 17 '14 15:09

Amit Chahar


People also ask

What is the problem of using large scopes of local variables?

There are several problems with local variables declared in too large scopes. One is that the variable may be declared but never used, as is the case if someCondition in the above example is false. Since declarations of variables in many cases costs computational cycles, you may end up wasting time for nothing.

How do you resolve local variable defined in an enclosing scope must be final or effectively final error?

If the value had been changed, the exception Local variable name defined in an enclosing scope must be final or effectively final would have been thrown. The work around is to create a new list and assign the local variable in it. The value can be modified either within or outside the lamda expression in the list.

What are the 3 three places of scope variables?

A scope is a region of the program and broadly speaking there are three places, where variables can be declared: Inside a function or a block which is called local variables, In the definition of function parameters which is called formal parameters.


1 Answers

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();        } }); 
like image 159
dic19 Avatar answered Oct 02 '22 12:10

dic19