Сонар: замените эту лямбда ссылкой на метод

Этот пример кода

Collection<Number> values = transform(
        getValuatedObjects(),
        input -> getValueProvider().apply(input).getValue());

нарушает правило sonarqube:

Замените лямбда с рекомендациями метода, если возможно

Это звуковая ошибка? или я действительно могу использовать ссылку на метод?

Ответ 1

Вы не можете заменить lambda input -> getValueProvider().apply(input).getValue() ссылкой на метод без изменения семантики.

Ссылка на метод заменяет один вызов метода, поэтому он не может просто заменить лямбда-выражение, состоящее из более чем одного вызова метода.

Лямбда-выражение формы input -> getValueProvider().apply(input) может быть заменено на getValueProvider()::apply, если и только если время оценки getValueProvider() не имеет значения, как в лямбдной форме, метод вызывается на каждой оценке лямбда-тела, тогда как для ссылки на метод он вызывается только один раз и результат улавливается.

Это похоже на разницу между x -> System.out.println(x) и System.out::println, где чтение содержимого поля System.out происходит в разное время, но обычно это не имеет значения. Но вы должны знать разницу.

В вашем примере вызывается третий метод getValue(). Единственный способ выразить это с помощью ссылок на методы требует функционального интерфейса, такого как Function, который имеет такие методы, как andThen и/или compose. Тем не менее, как работает Java 8, для чего требуется, чтобы первая ссылка метода на целевой интерфейс вызывала метод объединения, который отнюдь не будет легче читать, что теперь у вас есть лямбда-выражение: ((Function<X,Y>)getValueProvider()::apply).andThen(Y::getValue) где Y тип, apply(input) возвращает.

Обратите внимание, что правило гласит: "Замените лямбда с помощью ссылок на методы, когда это возможно", что дает вам возможность сказать "ну, здесь это невозможно", однако я не уверен, как много вы можете называть это "правилом" тогда...

Ответ 2

если вы кодируете в Java 8, вы можете использовать ссылку на метод вместо лямбда-выражения для читаемого кода

List<Integer> list = Arrays.asList(1,2,3,4,5);

замените эту лямбду ссылкой на метод

strList.stream().sorted().collect(Collectors.toList()).forEach(s -> System.out.println(s));

замещать

strList.stream().sorted().collect(Collectors.toList()).forEach(System.out::println);