A functional interface must have only one abstract method. However, it can have as many static and default methods as you'd like. The methods of Consumer
are:
accept(T)
- This is the single abstract method of
Consumer
. It accepts a single generic argument of type T
and returns nothing (i.e. void
). This is the method that's implemented by a lambda expression or method reference.
andThen(Consumer)
- This is a default method. In other words, it has an implementation and is thus non-abstract. The method accepts a
Consumer
and returns another Consumer
. Since it's a default method, the single abstract method of Consumer
remains accept(T)
.
The above explains why Consumer
can have a method that returns something other than void
. Now, when it comes to the implementation of andThen
, it's important to realize there are actually three Consumer
s involved:
- The instance on which
andThen
was invoked.
- The instance referenced by
after
.
- The instance returned to the caller.
If you format the code so not everything is on the same line it may be easier to follow:
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
// Returns Consumer instance #3. The lambda is the implementation
// of the 'accept' method.
return (T t) -> {
accept(t); // Invokes 'accept' on Consumer instance #1.
after.accept(t); // Invokes 'accept' on Consumer instance #2.
}
}