You didn’t define which “duplication” you are worrying about.
If it is the code duplication (or say, the fear about possible inconsistencies between the expressions which intentionally ought to be the same) that bothers you, you can use
Predicate<List<String>> predicate = (l) -> l.add("1");
Consumer<List<String>> consumer = predicate::test;
to avoid it.
If you want the lambda expressions to be really represented by the same instance, you may created a combined interface
:
interface PredicateAndConsumer<T> extends Predicate<T>, Consumer<T> {
public default void accept(T t) { test(t); }
}
PredicateAndConsumer<List<String>> pAndC = (l) -> l.add("1");
Predicate<List<String>> predicate = pAndC;
Consumer<List<String>> consumer = pAndC;
So, as you can see, you can use pAndC
in both contexts where either Predicate<List<String>>
or Consumer<List<String>>
is required.
However, there is little benefit in doing this. In this special case we can safely assume that for most JREs the overhead of introducing another interface
is higher than the saving of implementing it via one lambda expression.
You may also consider the answers to “Is method reference caching a good idea in Java 8?”. To summarize it, your example expressions do not capture values and therefore will be implemented as singletons in Oracle’s reference implementation (and will likely be as well in all alternative implementations). So here we are talking about whether there are one or two immutable constants created in the runtime environment…