TL; DR, este es un error del compilador.
No existe una regla que otorgue prioridad a un método aplicable en particular cuando se hereda o un método predeterminado. Curiosamente, cuando cambio el código a
interface ConsumerOne<T> {
void accept(T a);
}
interface ConsumerTwo<T> {
void accept(T a);
}
interface CustomIterable<T> extends Iterable<T> {
void forEach(ConsumerOne<? super T> c); //overload
void forEach(ConsumerTwo<? super T> c); //another overload
}
La iterable.forEach((A a) -> aList.add(a));
declaración produce un error en Eclipse.
Como ninguna propiedad del forEach(Consumer<? super T) c)
método desde la Iterable<T>
interfaz cambió cuando se declara otra sobrecarga, la decisión de Eclipse de seleccionar este método no puede basarse (de manera consistente) en ninguna propiedad del método. Sigue siendo el único método heredado, sigue siendo el único default
método, sigue siendo el único método JDK, etc. Ninguna de estas propiedades debería afectar la selección del método de todos modos.
Tenga en cuenta que cambiar la declaración a
interface CustomIterable<T> {
void forEach(ConsumerOne<? super T> c);
default void forEach(ConsumerTwo<? super T> c) {}
}
también produce un error "ambiguo", por lo que el número de métodos sobrecargados aplicables tampoco importa, incluso cuando solo hay dos candidatos, no hay preferencia general hacia los default
métodos.
Hasta ahora, el problema parece aparecer cuando hay dos métodos aplicables y un default
método y una relación de herencia están involucrados, pero este no es el lugar correcto para profundizar.
Pero es comprensible que las construcciones de su ejemplo puedan ser manejadas por diferentes códigos de implementación en el compilador, uno exhibiendo un error mientras que el otro no.
a -> aList.add(a)
es una expresión lambda escrita implícitamente , que no se puede usar para la resolución de sobrecarga. Por el contrario, (A a) -> aList.add(a)
es una expresión lambda escrita explícitamente que se puede usar para seleccionar un método coincidente de los métodos sobrecargados, pero no ayuda aquí (no debería ayudar aquí), ya que todos los métodos tienen tipos de parámetros con exactamente la misma firma funcional .
Como contraejemplo, con
static void forEach(Consumer<String> c) {}
static void forEach(Predicate<String> c) {}
{
forEach(s -> s.isEmpty());
forEach((String s) -> s.isEmpty());
}
las firmas funcionales difieren, y el uso de una expresión lambda de tipo explícito puede ayudar a seleccionar el método correcto, mientras que la expresión lambda escrita implícitamente no ayuda, por lo que forEach(s -> s.isEmpty())
produce un error de compilación. Y todos los compiladores de Java están de acuerdo con eso.
Tenga en cuenta que aList::add
es una referencia de método ambigua, ya que el add
método también está sobrecargado, por lo que tampoco puede ayudar a seleccionar un método, pero las referencias de método pueden ser procesadas por un código diferente de todos modos. El cambio a una ambigua aList::contains
o cambiar List
a Collection
, para que add
no ambigua, no cambió el resultado en mi instalación de Eclipse (utilicé 2019-06
).