user2070369
user2070369

Reputation: 4128

Java and closures

I was translating some code with a closure from C# to Java but I got an error, the code is this:

public ArrayList<String> getData(){
    String pSentence = "SELECT * FROM EMPLOYEES";
     ArrayList<String> pList = null;
    _con.queryFB(pSentence, (PreparedStatement ps, ResultSet rs) -> {

        pList = new ArrayList<>();

        try {
            rs = ps.executeQuery();

            while (rs.next()) {
                pList.add(rs.getString(1) + " : " + rs.getString(2) + " : " + rs.getString(3));
            }
        }
        catch (Exception ex) {
        }
    });
    return pList;
}

This is just a closure to execute a query, the closure just make sure that the connection to the database get always closed, but I get the error that "pList" method variable must be final to be used in the closure, a problem I don't have with C#, ok, I make it final and I get a new error that final var pList cannot be modified, so, what I do is move pList out of the method and put it in a private variable like this:

private ArrayList<String> pList = null;

public ArrayList<String> getData(){
    String pSentence = "SELECT * FROM EMPLOYEES";

    _con.queryFB(pSentence, (PreparedStatement ps, ResultSet rs) -> {

        pList = new ArrayList<>();

        try {
            rs = ps.executeQuery();

            while (rs.next()) {
                pList.add(rs.getString(1) + " : " + rs.getString(2) + " : " + rs.getString(3));
            }
        }
        catch (Exception ex) {
        }
    });
    return pList;
}

And then it Works, but, I'd like to know if there will be a memory leak or to know if there is a better way to do it, thanks.

Upvotes: 1

Views: 71

Answers (3)

joshng
joshng

Reputation: 1540

You are assigning the pList inside the closure, which is disallowed in java for variables declared outside. Try constructing the ArrayList in the variable initializer (List<String> pList = new ArrayList<>();), then consider clearing it at the top of your callback (if your database utility performs retries).

Incidentally, a decent connection-management utility should allow you to return your result directly from the callback-closure; I'd recommend looking into that approach, to avoid these concerns entirely.

Upvotes: 1

FDaumas
FDaumas

Reputation: 306

if you want to use pList outside the method, then define it outside, but use instead another variable inside the method. This inner variable will be deleted after the method finishes, by the garbage collector so would be something like this:

private List<String> pList = getData();
// ... do what you want with it

public List<String> getData() {
    public List<String> innerPList = new ArrayList<String>();
    String pSentence = "SELECT * FROM EMPLOYEES";
    _con.queryFB(pSentence, (PreparedStatement ps, ResultSet rs) -> {
    pList = new ArrayList<>();

    try {
        rs = ps.executeQuery();
        while (rs.next()) {
            innerPList.add(rs.getString(1) + " : " + rs.getString(2) + " : " + rs.getString(3));
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }

    return innerPList;
});

Upvotes: 1

Gudmundur Orn
Gudmundur Orn

Reputation: 2003

Your function should not both return the result and also assign it to a member variable. It is enough to return the result. In that case, pList can be a local variable.

If you want to cache the result, do that in another function which calls getData()

Upvotes: 0

Related Questions