Day eighty-six
Passing functions in Java
I had some duplication in my Pokemon Manager that I couldn’t work out how to fix, and Felipe helped me work out how to do it, so I thought I’d blog about it.
The duplication was in the class that dealt with communicating with the database. The basic layout for a method was this:
public void save(String name, String height) {
Connection connection = getConnection(); // connect to database
Statment statement = connection.createStatement(); // create a statement
String sql = "INSERT INTO POKEMON (name, height) VALUES " + name + "," + height + ";";
statement.execute(sql); // do something to the database
connection.close();
statement.close();
}
As I added more methods, I refectored them to look more like this:
public void save(String name, String height) {
Connection connection = getConnection();
Statment statement = connection.createStatement();
savePokemon(name, height, statement); // generalize the method called
connection.close();
statement.close();
}
public List<Pokemon> getPokemon() {
Connection connection = getConnection();
Statment statement = connection.createStatement();
List<Pokemon> pokemon = getPokemon(statement);
connection.close();
statement.close();
}
Which made it easier to see the pattern in my methods. The problem was that the thing that was changing in each method was the action required, and I had no idea how to pass that action into a method.
Felipe told me about java Function. I hadn’t used it before, but it allows you to pass a function into a method as an argument, as long as you specify what the function takes in, and what it passes out, so I could do something like this:
private <T> T runInConnection(Function<Statement, T> operation) {
Connection connection = getConnection();
Statement statement = connection.createStatement();
T returnValue = operation.apply();
connection.close();
statement.close();
return returnValue;
}
So now I can pass in the methods that actually execute what I want, and to do this, I used lambdas.
public void save(String name, String height) {
runInConnection(statement -> savePokemon(name, height, statement));
}
public List<Pokemon> getPokemon() {
return runInConnection(statement -> getPokemon(statment));
}
So I can call the method, pass the statement in, and leave the resposibility of creating a connection and closing a connection in one place, instead of having to recreate the connection in every method that needs to communicate with my database.