Я хотел бы иметь функциональный интерфейс, который принимает несколько различных типов лямбда-функций.
Я прочитал это. Первый ответ на этот вопрос поясняет, почему перегрузка абстрактного метода в функциональном интерфейсе может привести к неопределенному поведению. Однако есть ли способ перегрузить сделать эквивалент абстрактный метод в функциональном интерфейсе, если я укажу все значения по умолчанию?
Я хотел бы иметь возможность написать что-то вроде следующего кода:
Ball b = () -> System.out.println("You hit it!");
Ball ba = (boolean miss) -> System.out.println(miss);
b.hit();
b.hit(false);
ba.hit();
ba.hit(false);
Желаемый результат:
You hit it!
default false
default hit
false
Рассмотрим следующий (не компилируемый) код (в основном скопированный из связанного вопроса):
@FunctionalInterface
public interface Ball
{
void hit();
void hit(boolean miss);
default void hit(){
System.out.println("default hit");
}
default void hit(boolean miss){
System.out.println("default" + miss);
}
}
Я ищу альтернативу этому коду, который будет компилироваться.
Обратите внимание, что у вас не может быть двух определений метода в интерфейсе, даже если одно из них абстрактное, а другое используется по умолчанию. Вы пробовали компилировать свой код? Не думаю, что он скомпилируется. @Йехуда
@KartikSoneji Как было написано в вопросе, код не компилируется. Я ищу способ создать что-то эквивалентное.
Первое, что касается функционального интерфейса, это то, что он может иметь только один абстрактный метод. В этом случае вы даже не можете думать о втором методе (пусть это тоже будет абстрактный метод). у вас может быть любое количество методов по умолчанию.
Таким образом, ответ на 100% невозможен, и ваш код выше получит ошибку компиляции, поскольку вы сохранили аннотацию @FunctionalInterface, которая строго запрещает хранить более одного абстрактного метода. Согласно вашему коду
@FunctionalInterface
public interface MyInter {
public abstract void fly();
public abstract void fly(int a);
default void fly() {} \\line1
default void fly(int g) { } \\line2
}
строки 1 и 2 вызовут ошибку времени компиляции, так как java видит их по имени метода одинаковым и типам аргументов одинаковым, они никогда не будут беспокоиться о возвращаемом типе или значении по умолчанию или т. д. (основное правило перегрузки).
более того, если удалить строки 1 и 2, код тоже выдаст ошибку, потому что @functionalinterface выдаст ошибку компиляции с указанием недопустимая аннотация @FunctionalInterface; MyInter не является функциональным интерфейсом.
Надеюсь, что это ответ на ваш вопрос...
Вы могли бы сделать что-то вроде этого. Но вам нужно будет правильно назвать свои переменные, чтобы отслеживать как arg
, так и consumer
, которые их принимают.
@FunctionalInterface
interface Ball<T> {
void hit();
static <T> Ball<T> withArg(T arg, Consumer<T> com) {
return () -> com.accept(arg);
}
}
public class Demo {
public static void main(String[] args) {
Ball<Boolean> b = () -> System.out.println("You Hit it!");
b.hit();
Ball<Boolean> ba = Ball.withArg(false, a -> System.out.println(a));
Ball<Boolean> bb = Ball.withArg(true, a -> System.out.println(a));
ba.hit();
bb.hit();
}
}
Вы можете обернуть интерфейс в класс, а затем передать вызовы методов интерфейсам внутри.
Пример кода:
public class Test{
public static void main(String... args) throws Exception{
Ball b = new Ball(() -> System.out.println("You hit it!"));
Ball ba = new Ball((boolean miss) -> System.out.println(miss));
b.hit();
b.hit(false);
ba.hit();
ba.hit(false);
}
public static class Ball{
final Hit a;
final HitBoolean b;
public Ball(Hit a){
this.a = a;
b = (miss) -> System.out.println("default " + miss);
}
public Ball(HitBoolean b){
this.b = b;
a = () -> System.out.println("default hit");
}
public void hit(){
a.hit();
}
public void hit(boolean miss){
b.hit(miss);
}
}
public interface Hit{
void hit();
}
public interface HitBoolean{
void hit(boolean miss);
}
}
Вывод программы:
You hit it!
default false
default hit
false
Функциональный интерфейс допускает только один абстрактный метод. Как вы ожидаете, что это сработает?