web-dev-qa-db-fra.com

Lambda ne peut être utilisé qu'avec une interface fonctionnelle?

J'ai fait ça:

public class LambdaConflict
{
    public static void main(String args[]){
        //*
        System.out.println(LambdaConflict.get(
            (str) -> "Hello World!! By ME?"
        ));
        /*/
        System.out.println(LambdaConflict.get(new Intf<String> (){
            @Override public String get1(String str){
                return "Hello World!! By get1 " + str;
            }
        }));
        /*****/
    }

    public static String get(Intf<String> i, boolean b){
        return i.get1("from 1");
    }
}

interface Intf<T>
{
    public T get1(T arg1);

    public T get2(T arg1);
}

et obtenez cette exception:

types incompatibles: Intf n'est pas une interface fonctionnelle, plusieurs méthodes abstraites non prioritaires se trouvant dans l'interface Intf Remarque: Certains messages ont été simplifiés; recompiler avec -Xdiags: verbeux pour obtenir la sortie complète 1 erreur

Existe-t-il une condition selon laquelle je ne peux pas utiliser lambda pour remplacer une classe anonyme?

14
Valen

Non. Il n'y a aucun moyen de "surmonter" cela. Une interface fonctionnelle ne doit avoir qu'une seule méthode abstraite. Votre interface en a deux:

interface Intf<T> {
    public T get1(T arg1);
    public T get2(T arg1);
}

Remarque: vous n'avez pas besoin d'annoter votre interface comme mentionné dans les commentaires. Mais vous pouvez utiliser le @FunctionalInterface annotation pour obtenir des erreurs de compilation si votre interface n'est pas une interface fonctionnelle valide. Cela vous apporte donc un peu plus de sécurité dans votre code.

Pour plus d'informations, voir par exemple http://Java.dzone.com/articles/introduction-functional-1

20
Thomas Uhrig

Juste pour référence et pour enrichir les réponses déjà données:

Selon JSR-335: Expressions Lambda pour le Java langage de programmation , dans la section Spécifications Lambda, Partie A: Interfaces fonctionnelles, il est dit:

Une interface fonctionnelle est une interface qui n'a qu'une seule méthode abstraite (en dehors des méthodes d'Object), et représente donc un contrat de fonction unique. (Dans certains cas, cette méthode "unique" peut prendre la forme de plusieurs méthodes abstraites avec des signatures équivalentes de substitution héritées des superinterfaces; dans ce cas, les méthodes héritées représentent logiquement une seule méthode.)

Donc, ce dont vous avez besoin est de fournir une implémentation par défaut pour l'une de vos méthodes ou de placer l'une de vos méthodes dans une interface différente.

7
Edwin Dalorzo

Pensez-y:

  • Comment le compilateur doit-il savoir si vous souhaitez remplacer get1 ou get2?

  • Si vous remplacez uniquement get1, ce qui sera get2 la mise en œuvre? Même le code que vous avez commenté ne fonctionnera pas car vous n'implémentez pas get2...

Il y a des raisons à cette limitation ...

3
Idan Arye

Comme indiqué par @ Thomas-Uhrig, les interfaces fonctionnelles ne peuvent avoir que ne méthode.

Un moyen de résoudre ce problème, principalement parce que vous n'utilisez jamais public T get2(T arg1);, consiste à modifier le Intf<T> interface vers:

@FunctionalInterface
interface Intf<T>
{
    public T get1(T arg1);
}
1
DirkyJerky