Обычная лямбда функция
a -> foo(a)
работает понятно и логично, в отличие от оператора двоеточия. Вот два примера:
1 пример:
// с использованием ::
list.forEach(System.out::println);
// то же самое, но обычной лямбдой
list.forEach(n -> System.out.println(n));
Исходя из этого примера, можно сказать, что (::) принимает только один аргумент и автоматически подставляет его в функции println класса System.out.
А теперь 2 пример:
map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey);
// Исходя из логики первого примера, эквивалентно, используя лямбду, можно было бы заменить так:
map.entrySet().stream().collect(Collectors.toMap(a -> Map.Entry.getKey(a)); // однако очевидно, что это неправильно, и правильно будет так:
map.entrySet().stream().collect(Collectors.toMap(a -> a.getKey());
Отсюда вопросы:
как :: определяет, как именно необходимо вызывать метод(System.out.println(n) или n.getKey() )?
как :: может работать с несколькими аргументами?
какой у него вообще принцип работы?