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 Consumers 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.
}
}