7

Je suis perplexe sur les constructeurs SAM, j'ai cette classe Java:ne peut pas remplacer constructeur SAM avec lambda quand le premier argument est une classe avec une méthode

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 { 
    } 
} 

Et ce code Kotlin:

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 
} 

Quelle est la situation ici? Pourquoi Kotlin ne peut pas comprendre 3. (et fournit la variante spéciale 4.), mais gère tous les autres cas?


La justification de ce code est procédé LiveData<T>.observe(LifecycleOwner owner, Observer<T> observer) dans les applications où LifecycleOwner a une méthode getLifecycle().

Répondre

2

Je trouve une règle dans le compilateur: si appel Java méthode requiert des types qui est SAM-interfaces, vous pouvez les remplacer par des lambdas (ou fonctions), mais soit tous ces paramètres, ou aucun d'eux.

Donc, vous avez la méthode: public void observe(OneMethod one, Observer<T> observer). Les deux paramètres sont des candidats SAM. Vous pouvez appeler:
observer(object1, object2)
ou:
observer(function1, function2)

mais pas:
observer(object1, function2)
et pas:
observer(function1, object2)

Même comportement sera même en cas de 3 ou plus de paramètres. La cause de ceci est la difficulté technique dans la conception de compilateur. Désolé si je ne suis pas très clair, je ne suis pas très bon en anglais.

+0

Pouvez-vous ajouter un lien vers le code source du compilateur? (Ou à une spécification où cela est expliqué?) (Ou avez-vous trouvé la réponse en l'essayant?) – Marco13

+0

Je pense que ce n'est pas vraiment documenté, juste essayé moi-même. Pour plus de précision, il est préférable de demander aux développeurs Kotlin. L'un d'entre eux m'a dit ce qu'il y avait un problème dans bug tracker pour cela. – Beholder

+0

Oh, je pense que j'ai compris. Le problème est que mon 'OneMethod' et' LifecycleOwner' d'Android sont des interfaces SAM. Dommage que ce soit seulement par accident, vraiment, parce que je doute que 'LifecycleOwner' soit utilisé comme' Runnable' est utilisé par exemple, nous ne définirions jamais de classes anonymes pour cela en Java, l'interface est implémentée par 'AppCompatActivity' classe de base. – arekolek