Using Lambdas to implement a function table

When I implemented an expression parser for arithmetic expressions (such as t*x+sin(x-5) + π), one part was to create a symbol table to look up constant values such as π, variables such as x and t, but also functions like sin(x). My initial approach had this structure:

 

This allowed me to create a symbol table as a HashMap, and then to add variables, constants or functions into the table:

private Map<String, Symbol> table = new HashMap<>();
...
table.put("sin",  new SinFunction());
table.put("log",  new LogFunction());
...

This works well, but requires a whole new class for each new function, where each of the classes simply provides a getValue() method which delegates to the corresponding static method from Math:

public double getValue(double arg) {
   return Math.sin(arg);
}

Using lambda expressions, the class structure can be much simplified:

Instead of an abstract class Function with specific sub classes which implement the getValue() method, we provide a concrete Function class which delegates to the functional interface DoubleFunction. The instantiation of the Function objects can then be moved into the SymbolTable class, essentially as a convenient method:

public void putSymbol(String name, DoubleFunction<Double> fun) {
   table.put(name, new Function(name, fun));
}

Now, adding new function to the symbol table is straight forward, using a lambda expression:

symbolTable.putSymbol("sin", x -> Math.sin(x));
symbolTable.putSymbol("log", x -> Math.log(x));

Especially we do not need to add another class when adding a new function. The class structure of the symbol table remains stable, all we need is to register the new function through a call to SymbolTable.putSymbol(). Besides simply mapping a function name to a method from the Math class, this works equally well for any user defined function, for example:

symbolTable.putSymbol("f1", x -> x*x + 42*x + 19);
symbolTable.putSymbol("f2", x -> Math.cos(x*x) + 42*x);

Since the Function class holds a reference to the lambda expression through the DoubleFunction interface, we simply call the DoubleFunction.apply() method to evaluate the function for a given x value:

public class Function extends Symbol {

   private DoubleFunction<Double> theFunc;

   ...

   @Override
   public double getValue(double x) {
      return theFunc.apply(x);
   }
}