Подтвердить что ты не робот

Java 8, Lambda: заменить анонимный внутренний класс лямбдой

У меня есть класс, который содержит следующее:

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

IntelliJ говорит мне заменить анонимный внутренний класс лямбдой. Поэтому я попробовал:

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

Однако я получаю ошибку компиляции:

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

Я не могу найти решение этой проблемы. У вас есть идеи?

4b9b3361

Ответ 1

Попробуйте сделать это (удаляя лишние двоеточие)

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

Ответ 2

Простой лазурный интерфейс Entity Resolver и реализованный метод:

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();
    }
  };

Лямбда вышеуказанного метода будет:

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

Из вышеприведенного примера видно, что лямбда достаточно умен, чтобы обрабатывать тип параметров метода в соответствии с их анонимным внутренним классом, тем самым упрощая реализацию переопределенного метода. Надеюсь, это будет полезно.

Ответ 3

У меня сильное чувство, что вы не опубликовали точный код в своем вопросе. Как Bart, я не могу воспроизвести ошибку с кодом, который вы опубликовали.

Однако, что меня поражает, это использование вами сырых типов. Если ваш исходный код выглядел так:

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

(обратите внимание на измененный тип переменной roles), вы получите просто предупреждение типа raw, когда вы внедрили AttributesMapper без аргументов типа, и не будет проверки, будет ли возвращенный Object действителен как элемент для a List<String>.

При преобразовании этого кода в лямбда вам больше не избежать:

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

Теперь компилятор выведет тип AttributesMapper<String> для вас и создаст ошибку, потому что ваше выражение лямбда возвращает Object вместо String и, следовательно, не выполняет интерфейс AttributesMapper<String>.

Вы можете исправить это, либо вставив тип, чтобы выполнить интерфейс AttributesMapper<String>, либо объявив roles необработанным типом List, как вы уже делали в вопросе. Однако использование типа cast будет более чистым способом (и должно быть единственным, которое не создает предупреждений компилятора):

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

(Я упростил выражение для компенсации включенного типа, выглядит намного лучше, не так ли?)