Lambda Best Practices
When people are first picking up object-oriented programming, there is a tendency to go nuts with
inheritance. The language feature is so cool that you end up with layers upon layers of inheritance, and as a
result, code becomes extremely difficult to follow and maintain. A similar thing happens with lambdas. At
this point, you know enough about lambdas to be dangerous, and you will probably be overexcited to apply
this newfound knowledge and use functional interfaces everywhere. That enthusiasm is great, but before
you go out and lamdify all your code, let me give you some words of caution.
The most common misstep taken by an over-eager functional programmer is the use of functional interfaces
in type signatures. In general, you should avoid using the functional interface types directly and instead
provide single-method interfaces as arguments to your methods. These interfaces become a way to create
self-documenting code and to provide meaningful type information, as well as leaving open the opportunity
for your user to provide an actual Java type. If they want to implement your interface using lambdas and
method references, they can still do that, but don't force them to.
Consider the two method signatures: processFile(LineHandler handler) and
processFile(Consumer<String> handler) . In the latter case, it's not obvious what the String provides,
or what the consumer is expected to do. Even more than that, though, if you later want to provide a
processFile(FileHandler handler) method, then you can, whereas you would end up with conflicting
types in the other case.
Use Method References
As much as possible, use a method reference instead of a lambda. Method references are not only shorter
and easier to read, but using method references will get you thinking directly about the methods as values.
This is the code you need to excise from your codebase and your brain:
x -> it.do(x)
If you are naturally writing that code, then you still have not made the leap to thinking at the higher level
of functional programming. Once you make that leap, it will become much easier to communicate and work
with complex functions, because you will be thinking in types, not in values.
Define Lambdas Inline
When you do use lambdas, define them inline. Unless you are doing some kind of fancy manipulation of your
lambda, there is no reason to be assigning them to a variable. The reason that you want to define your lambdas
inline is that it will allow your code to be more flexible when types change: you are letting type inference do
more heavy lifting for you, and adapting your code to changing contexts. If you start assigning your lambdas to
variables, you will have to start being explicit with types, and that is needlessly solidifying your types.
Lambdas Should Always Be Threadsafe
As we go through the rest of this topic, we will see many places where lambdas make concurrent programming
much easier. Many of the structures built off of lambdas will perform concurrent executions, sometimes without
much warning. Because of this, your lambdas always need to be threadsafe. Pay particular attention to this with
instance method handles, since thread-dangerous state can often be hiding within those instances.