web-dev-qa-db-fra.com

Problèmes avec la portée de la variable locale. Comment le résoudre?

L'erreur suivante s'affiche lorsque j'essaie d'exécuter statemet.executeUpdate() dans mon code:

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

C'est mon code jusqu'à présent:

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");

    }
}

J'ai aussi essayé de définir statement final mais la déclaration me donne une autre erreur.

45
Amit Chahar

Vous avez effectivement un problème de portée, car statement est une variable de méthode locale définie ici:

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();
            }
            ...
    });
}

Lorsque vous essayez d'accéder à cette variable dans la méthode mouseDown(), vous essayez d'accéder à une variable locale depuis une classe interne anonyme et la portée ne suffit pas. Donc, il doit absolument être final (ce qui compte tenu de votre code n'est pas possible) ou déclaré en tant que membre de la classe pour que la classe interne puisse accéder à cette variable statement.

Sources:


Comment le résoudre?

Vous pourriez...

Faites de statement un membre de la classe au lieu d'une variable locale:

public class A1 { // Note Java Code Convention, also class name should be meaningful   
    private Statement statement;
    ...
}

Vous pourriez...

Définissez une autre variable finale et utilisez celle-ci, comme suggéré par @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();
    }
    ...
}

Mais tu devrais...

Reconsidérer votre approche. Si la variable statement ne sera pas utilisée tant que le bouton btnInsert n'aura pas été actionné, il est alors inutile de créer une connexion avant, ce qui se produit réellement. Vous pouvez utiliser toutes les variables locales comme ceci:

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();
       }
});
74
dic19

Il existe également une troisième solution à ce problème, autre que de la rendre finale ou de déclarer la variable inaccessible en tant que membre de la classe, car ces options ne sont pas toujours possibles ni souhaitables.

Tout d'abord, nous ne POUVONS PAS rendre la variable finale car son état peut changer pendant l'exécution du programme et nos décisions dans la substitution de classe interne peuvent dépendre de son état actuel.

Deuxièmement, une bonne pratique de programmation orientée objet suggère d'utiliser uniquement des variables/constantes essentielles à la définition de la classe en tant que membres de la classe. Cela signifie que si la variable que nous référons dans la classe interne anonyme, la substitution est simplement une variable d’utilitaire, elle ne doit pas être répertoriée parmi les membres de la classe.

Donc, à partir de Java 8, nous avons maintenant une troisième option, décrite ici:

https://docs.Oracle.com/javase/tutorial/Java/javaOO/localclasses.html

A partir de Java SE 8, si vous déclarez la classe locale dans une méthode, celle-ci peut accéder aux paramètres de la méthode.

Nous pouvons donc maintenant simplement insérer le code contenant la nouvelle classe inner et sa substitution de méthode dans une méthode statique privée dont les paramètres incluent la variable que nous appelons depuis l'intérieur de la substitution. Cette méthode statique est ensuite appelée après l'instruction de déclaration btnInsert: -

 // Original code :
 Button btnInsert = new Button(Shell, SWT.NONE);
 // Call to new private static method :
 addMouseListener(Button btnInsert, Statement statement);

 . . . 
 . . .
 . . . 

 // New private static method to give access to query statement :
 private static void addMouseListener(Button btn, Statement st)
 {
    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) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
    }
  });
  return;
}

 . . . .
 . . . .
 . . . .
3
Trunk

pas d'erreur:

JSONObject json1 = getJsonX();

Erreur:

JSONObject json2 = null;
if(x == y)
   json2 = getJSONX();

Erreur: L'instruction de variable locale définie dans une portée englobante doit être finale ou effective.

Mais vous pouvez écrire:

JSONObject json2 = (x == y) ? json2 = getJSONX() : null;
0
mehdi salartayefeh

J'ai trouvé cette approche utile. De cette façon, vous n'avez pas besoin d'un cours ni d'une finale

 btnInsert.addMouseListener(new MouseAdapter() {
        private Statement _statement;

        public MouseAdapter setStatement(Statement _stmnt)
        {
            _statement = _stmnt;
            return this;
        }
        @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();
            }
        }
    }.setStatement(statement));
0
user4212919