I added another answer here in response to Leventov's last comment about requiring an explicit cast, and am offering this advice. It may or may not be bad practice, but I have found it very useful for defining my own interfaces in some cases where I wanted to inject some pre-or-post processing or provide my own layer of abstraction overtop of somebody else's (for instance, we defined one like this for Hibernate's Work classes so that if Hibernate's API changes in the future, our implementations don't have to - only the default method in our Interface), and it might make life a bit easier with the two versions of the same interface.
Consider this: The beauty of the functional interface is that it has only one abstract method, so you can pass a lambda as that method's implementation.
But when you extend an interface, which you still want to have that same functionality (pass a lambda, and work in all cases), another beauty of Java 8 comes into play: Defender methods. Nothing anywhere says that you have to leave the SAME method abstract as the parent class did. You can extend an interface as a sort of interceptor interface. So you can define YOUR MyConsumer like this:
public interface MyConsumer<T> extends Consumer<T> {
default void accept(T t){ // Formerly the abstract functional method
getConsumer().accept(t);
}
public Consumer<T> getConsumer(); //Our new abstract functional method
}
Our interface, instead of defining accept(T) as an abstract method, implements accept(T), and defines an abstract method getConsumer(). This makes the lambda to instantiate a MyConsumer different from the one required to instantiate a j.u.f.Consumer, and removes the compiler's class conflict.
Then you can define your class that implements Iterable to instead implement your own custom interface extending Iterable.
public interface MyIterable<T> extends Iterable<T> {
default void each(MyConsumer<? super T> action){
//Iterable.super.forEach((Consumer<? super T>) action);
//
// Or whatever else we need to do for our special
// class processing
}
default void each(Consumer<? super T> action){
if (action instanceof MyConsumer){
each((MyConsumer<? super T>) action);
} else {
Iterable.super.forEach(action);
}
}
@Override
default void forEach(Consumer<? super T> action){
each(action);
}
}
It still has a forEach method, allowing it to comply to the iterable iterface, but all of your code can call each() instead of forEach() in all versions of YOUR api. This way you also partially future-proof your code - if the underlying Java api were to be deprecated years down the line, you could modify your default each() method to do things the new way, but in every other place all your existing implementation code will still be functionally correct.
Thus, when you call api.each, instead of requiring an explicit cast, you simply pass the lambda for the other method... in MyConsumer, the method returns a consumer, so your lambda is really simple, you just add the lambda zero-arg constructor to your previous statement. The accept() method in Consumer takes one argument and returns a void, so if you define it with no arguments, Java knows that it wants an interface that has an abstract method which takes no arguments, and this lambda instantiates MyConsumer.
api.each(()->System.out::println);
while this one instantiates j.u.f.Consumer
api.each(System.out::println);
Because the original abstract method (accept) is there, and implemented, it's still a valid instance of Consumer, and will work in all cases, but because we called the 0-arg constructor, we've explicitly made it an instance of our custom interface. This way, we still fulfill the interface contract of Consumer, but we can differentiate our interface's signature from Consumer's.