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);
}
}
```