web-dev-qa-db-fra.com

Java 8, Lambda: remplace la classe interne anonyme par lambda

J'ai une classe qui contient les éléments suivants:

List roles = ldapTemplate.search(baseDn, replaceFilter, sc,
            new AttributesMapper() {
                public Object mapFromAttributes(Attributes attrs)
                        throws NamingException {
                    return attrs.get("cn").get();
                }
            });

IntelliJ me dit de remplacer la classe interne anonyme par un lambda. Alors j'ai essayé:

List roles = ldapTemplate.search(
    baseDn, replaceFilter, sc,
    (Attributes a)  -> { return a.get("cn").get(); };
);

Cependant, je reçois une erreur de compilation:

Error:(46, 50) Java: incompatible types: inference variable T has incompatible bounds
    equality constraints: Java.lang.String
    lower bounds: Java.lang.Object

Je ne trouve pas la solution à ce problème. Avez-vous des idées?

31
user3934519

Une simple interface Azure Storage Entity Resolver et sa méthode implémentée:

EntityResolver<String> orderNumberResolver = new EntityResolver<String>() {
    @Override
    public String resolve(String partitionKey, String rowKey, Date timeStamp,
        HashMap<String, EntityProperty> properties, String etag) {
      return properties.get("SomeColumnName").getValueAsString();
    }
  };

Lambda de la méthode ci-dessus sera:

 EntityResolver<String> orderNumberResolver = (
          partitionKey, rowKey, timeStamp, properties, etag
      ) -> properties.get("SomeColumnName").getValueAsString();

Dans l'exemple ci-dessus, il est clair que les méthodes lambda sont suffisamment intelligentes pour gérer le type de paramètres de méthode en fonction de leur classe interne anonyme, ce qui facilite la mise en œuvre de la méthode surchargée. J'espère que cela vous sera utile.

17
Trilok Singh Devda

Essayez ceci (en supprimant le point-virgule supplémentaire)

List roles = ldapTemplate.search(
    baseDn, replaceFilter, sc,
    (Attributes a)  -> { return a.get("cn").get(); }            
);
15
snaikar

J'ai le fort sentiment que vous n'avez pas posté le code exact dans votre question. Comme Bart , je ne peux pas reproduire l'erreur avec le code tel que vous l'avez posté.

Cependant, ce qui me frappe, c'est votre utilisation de types bruts . Si votre code d'origine ressemblait à ceci:

List<String> roles = ldapTemplate.search(baseDn, replaceFilter, sc,
    new AttributesMapper() {
        public Object mapFromAttributes(Attributes attrs)
                throws NamingException {
            return attrs.get("cn").get();
        }
    });

(notez le type modifié de la variable roles) vous éviterez un avertissement de type brut lors de la mise en œuvre de AttributesMapper sans arguments de type et il n’y aura pas de moyen de vérifier si le Object renvoyé sera valide en tant qu’élément pour un List<String>.

Lorsque vous convertissez ce code en lambda, vous ne pouvez plus vous en tirer:

List<String> roles = ldapTemplate.search(baseDn, replaceFilter, sc,
  (Attributes a)  -> { return a.get("cn").get(); }            
);

Maintenant, le compilateur déduira le type AttributesMapper<String> pour vous et générez une erreur car votre expression lambda renvoie Object au lieu de String et ne remplit donc pas le AttributesMapper<String> interface.

Vous pouvez résoudre ce problème en insérant un transtypage pour remplir le AttributesMapper<String> interface ou en déclarant roles avec le type brut List comme vous l’avez déjà fait dans la question. Cependant, utiliser le transtypage sera plus propre (et devrait être le seul à ne pas produire d'avertissements du compilateur):

List<String> roles = ldapTemplate.search(baseDn, replaceFilter, sc,
    a -> (String)a.get("cn").get());

(J'ai simplifié l’expression pour compenser le transtypage inclus, ça a l'air beaucoup mieux, n'est-ce pas?)

4
Holger