Невозможно заменить SAM-конструктор лямбдой, когда первый аргумент – это класс с одним методом

Я озадачен конструкторами SAM, у меня есть этот класс Java:

public class TestSam<T> { public void observe(ZeroMethods zero, Observer<T> observer) { } public void observe(OneMethod one, Observer<T> observer) { } public void observe(TwoMethods two, Observer<T> observer) { } public interface Observer<T> { void onChanged(@Nullable T t); } public interface ZeroMethods { } public interface OneMethod { First getFirst(); } public interface TwoMethods { First getFirst(); Second getSecond(); } public interface First { } public interface Second { } } 

И этот код Котлина:

 fun testSam( test: TestSam<String>, zero: TestSam.ZeroMethods, one: TestSam.OneMethod, two: TestSam.TwoMethods ) { test.observe(zero) { println("onChanged $it") } // 1. compiles test.observe(zero, TestSam.Observer { println("onChanged $it") }) // 2. Redundant SAM-constructor test.observe(one) { println("onChanged $it") } // 3. doesn't compile test.observe({ one.first }) { println("onChanged $it") } // 4. compiles test.observe(one, TestSam.Observer { println("onChanged $it") }) // 5. compiles test.observe(two) { println("onChanged $it") } // 6. compiles test.observe(two, TestSam.Observer { println("onChanged $it") }) // 7. Redundant SAM-constructor } 

Какая сделка здесь? Почему Котлин не может определить 3. (и предоставляет специальный вариант 4.), но справляется со всеми другими случаями?


Обоснованием для этого кода является LiveData<T>.observe(LifecycleOwner owner, Observer<T> observer) в Android, где LifecycleOwner имеет один метод getLifecycle() .

Я нашел правило в компиляторе: если вызов Java-метода требует типов, которые являются SAM-интерфейсами, тогда вы можете заменить их lambdas (или функциями), но либо все такие параметры, либо ни один из них.

Итак, у вас есть метод: public void observe(OneMethod one, Observer<T> observer) . Оба параметра являются кандидатами SAM. Вы можете позвонить:
observer(object1, object2)
или:
observer(function1, function2)

но не :
observer(object1, function2)
а не :
observer(function1, object2)

Такое же поведение будет даже в случае 3 или более параметров. Причиной этого является технические трудности в дизайне компилятора.

Извините, если я не очень ясен, я не очень хорош на английском.