IntelliJ IDEA предлагает заменить лямбда-выражения ссылками на методы. В чём разница разница между ними?
Принципиальная разница вот в чём: лямбда - это всегда новый метод в классе. Если декомпилировать вот такой код:
Function<String, String> f = s -> s.toUpperCase();
f.apply("abc");
получим такой байткод:
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
// байткод main
private static java.lang.String lambda$main$0(java.lang.String);
descriptor: (Ljava/lang/String;)Ljava/lang/String;
flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
// байткод лямбды
Для сравнения, код со ссылкой на метод:
Function<String, String> f = String::toUpperCase;
f.apply("abc");
даст такой байткод:
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
// байткод main
Каждая лямбда в байткоде превращается в приватный синтетический метод с именем вроде lambda$0, который будет вызываться через invokedynamic каждый раз, когда нужна лямбда. Поэтому IDEA и советует вам заменить лямбду на ссылку на метод - так байткод класса будет компактнее, а значит, класс быстрее загрузится в JVM. Само собой, для того чтобы ощутить такой прирост, нужны тысячи неоптимизированных лямбд, но в крупном проекте такое количество наберётся легко.
В остальном выбор между лямбдой и ссылкой на метод - вопрос вкуса и читаемости кода. Например, если в лямбде несколько строк, читаемость снижается, и код только выиграет, если лямбду вынести в отдельный метод, и использовать ссылку на него. Или, например, если есть класс ClassWithVeryVeryVeryLongName с методом doSth(), то лямбда c -> c.doSth() будет читаться проще, чем ClassWithVeryVeryVeryLongName::doSth.
В лямбде вы вызываете метод, который принимает столько параметров сколько у лямбды с теми же типами. Поэтому его можно заменить ссылкой на метод, которая в свою очередь тоже является лямбдой.
Об этом более или менее подробно описано в примере:
Arrays.sort(rosterAsArray,
(a, b) -> Person.compareByAge(a, b)
);
Поскольку это лямбда-выражение вызывает существующий метод, вы можете использовать ссылку на метод вместо выражения лямбда:
Arrays.sort(rosterAsArray, Person::compareByAge);
Ссылка метода Person::compareByAge семантически совпадает с
выражением лямбда (a, b) -> Person.compareByAge(a, b). Каждый из
них имеет следующие характеристики:
Comparator<Person>.compare, который является (Person, Person). Person.compareByAge.Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости