::
называется ссылкой на метод. Это в основном ссылка на один метод. То есть он ссылается на существующий метод по имени.
Краткое пояснение: Ниже приведен пример ссылки на статический метод:
class Hey {
public static double square(double num){
return Math.pow(num, 2);
}
}
Function square = Hey::square;
double ans = square.apply(23d);
square
можно передавать так же, как ссылки на объекты и запускаются при необходимости. Фактически, его можно так же легко использовать в качестве ссылки на «нормальные» методы объектов как static
. Например:
class Hey {
public double square(double num) {
return Math.pow(num, 2);
}
}
Hey hey = new Hey();
Function square = hey::square;
double ans = square.apply(23d);
Function
выше - функциональный интерфейс. Чтобы полностью понять ::
, важно также понимать функциональные интерфейсы. По-видимому, функциональный интерфейс является интерфейсом только с одним абстрактным методом.
Примеры функциональных интерфейсов включают Runnable
, Callable
и ActionListener
.
Function
выше - функциональный интерфейс только с одним способом: apply
. Он принимает один аргумент и дает результат.
Причина, по которой ::
s является awesome, - , что :
Ссылки на методы являются выражениями, которые имеют такое же отношение к лямбда-выражениям (...), но вместо предоставления тела метода они ссылаются на существующий метод по имени.
Например вместо записи лямбда-тела
Function
square = (Double x) -> x * x; Вы можете просто выполнить
Function
square = Hey::square; Во время выполнения эти два метода
square
ведут себя точно так же, как и другие. Байт-код может быть или не быть одинаковым (хотя для вышеуказанного случая генерируется один и тот же байт-код, компилируется выше и проверяется с помощьюjavap -c
).Единственным основным критерием для удовлетворения является: метод, который вы предоставляете, должен иметь аналогичную подпись для метода функционального интерфейса, который вы используете в качестве ссылки на объект .
Ниже указано незаконное:
Supplier
p = Hey::square; // illegal
square
ожидает аргумент и возвращает значениеdouble
. Методget
в Поставщик ожидает аргумент, но ничего не возвращает. Таким образом, это приводит к ошибке.Ссылка на метод относится к методу функционального интерфейса. (Как уже упоминалось, функциональные интерфейсы могут иметь только один метод).
Еще несколько примеров: метод
accept
в Пользователь принимает ввод, но ничего не возвращает.Consumer
b1 = System::exit; // void exit(int status) Consumer b2 = Arrays::sort; // void sort(Object[] a) Consumer b3 = MyProgram::main; // void main(String... args) class Hey { public double getRandom() { return Math.random(); } } Callable call = hey::getRandom; Supplier call2 = hey::getRandom; DoubleSupplier sup = hey::getRandom; // Supplier is functional interface that takes no argument and gives a result Выше
getRandom
не принимает аргументов и возвращаетdouble
. Таким образом, любой функциональный интерфейс, который удовлетворяет критериям: , не принимает аргументов и возвращаетdouble
.Другой пример:
Set
set = new HashSet<>(); set.addAll(Arrays.asList("leo","bale","hanks")); Predicate pred = set::contains; boolean exists = pred.test("leo"); В случае параметризованных типов:
class Param
{ T elem; public T get() { return elem; } public void set(T elem) { this.elem = elem; } public static E returnSame(E elem) { return elem; } } Supplier> obj = Param ::new; Param param = obj.get(); Consumer c = param::set; Supplier s = param::get; Function func = Param:: returnSame; Ссылки на методы могут иметь разные стили, но в корне они все означают одинаковые вещь и может быть просто визуализирована как lambdas:
- Статический метод (
ClassName::methName
)- Метод экземпляра конкретного объекта (
instanceRef::methName
)- Супер метод конкретного объекта (
super::methName
)- Метод экземпляра произвольного объекта определенного типа (
ClassName::methName
)- Ссылка на конструктор класса (
ClassName::new
)- Ссылка на конструктор массива (
TypeName[]::new
)Дальнейшую ссылку см. в http://cr.openjdk.java.net /~briangoetz/lambda/lambda-state-final.html.