Book/Effective Java

[Effective Java] Item 42: Prefer lambda to anonymous classes

hajinny 2021. 11. 7. 14:10

In the previous post (Item 38: emulate extensible enums with interfaces), we had an enum declaration that implements different behaviour of overriden method for each enum instance. Just to refresh memory, here's what we had:

An advantage of this is extreme flexibility - GradeCalculable interface's abstract method is implemented all differently for each enum instance. However, the fallpit of this design is that we need @Override and method signature for each and every enum, making the declaration extremely verbose.

 

Lambda allows us to heavily refactor this.

Here's what we did:

1. Instead of overriding the abstract method at each enum instance, we override it at the enum 'class' level. This overriding was already possible before, but we didn't use it because we could not implement custom behaviour of 'calculateGrade' method for each enum instance.

2. Make each enum pass in lambda to its constructor, and store their behaviour to their field 'gradeCalculator. The overriden calculateGrade() simply invokes 'gradeCalculator.apply(percentage)'.

 

This is a template method pattern* - calculateGrade() depends on Function<Float,Grade> gradeCalculator instance field of enum.

* I'm still not completely certain about the difference between template method pattern and strategy pattern. But it seems that:
- Strategy pattern is where you have different implementations of interface (that specifies set of behaviours) and you can swap that strategy at runtime
- Template method pattern is where you have a method that relies a part of its behaviour on subclassing implementations (eg A() could rely on B() that is overriden. It's usually fixed for one concrete implementation (you can't swap out B()).

You can see that lambda really refactored the original code so that verbosity is kept to what is necessary.