::
được gọi là Phương thức tham khảo. Nó về cơ bản là một tham chiếu đến một phương pháp duy nhất. Tức là nó đề cập đến một phương thức hiện có theo tên.
Giải thích ngắn :
Dưới đây là ví dụ về tham chiếu đến phương thức tĩnh:
class Hey {
public static double square(double num){
return Math.pow(num, 2);
}
}
Function<Double, Double> square = Hey::square;
double ans = square.apply(23d);
square
có thể được truyền xung quanh giống như tham chiếu đối tượng và được kích hoạt khi cần. Trong thực tế, nó có thể dễ dàng được sử dụng như một tham chiếu đến các phương thức "thông thường" của các đối tượng như các phương thức static
. Ví dụ:
class Hey {
public double square(double num) {
return Math.pow(num, 2);
}
}
Hey hey = new Hey();
Function<Double, Double> square = hey::square;
double ans = square.apply(23d);
Function
ở trên là giao diện chức năng . Để hiểu đầy đủ ::
, điều quan trọng là phải hiểu giao diện chức năng là tốt. Rõ ràng, một giao diện chức năng là một giao diện chỉ với một phương thức trừu tượng.
Ví dụ về các giao diện chức năng bao gồm Runnable
, Callable
và ActionListener
.
Function
ở trên là một giao diện chức năng chỉ với một phương thức : apply
. Nó nhận một đối số và tạo ra một kết quả.
Lý do tại sao ::
s là tuyệt vời là rằng :
Tham chiếu phương thức là các biểu thức có cùng cách xử lý với biểu thức lambda (...), nhưng thay vì cung cấp phần thân phương thức, chúng tham chiếu một phương thức hiện có theo tên.
Ví dụ, thay vì viết cơ thể lambda
Function<Double, Double> square = (Double x) -> x * x;
Bạn chỉ có thể làm
Function<Double, Double> square = Hey::square;
Trong thời gian chạy, hai square
phương thức này hoạt động giống hệt nhau. Mã byte có thể hoặc không giống nhau (mặc dù, đối với trường hợp trên, mã byte tương tự được tạo ra; biên dịch mã ở trên và kiểm tra với javap -c
).
Tiêu chí chính duy nhất để đáp ứng là: phương thức bạn cung cấp phải có chữ ký tương tự như phương thức của giao diện chức năng bạn sử dụng làm tham chiếu đối tượng .
Dưới đây là bất hợp pháp:
Supplier<Boolean> p = Hey::square; // illegal
square
mong đợi một đối số và trả về a double
. Các get
phương pháp trong Nhà cung cấp trả về giá trị nhưng không mất một cuộc tranh cãi. Do đó, điều này dẫn đến một lỗi.
Một tham chiếu phương thức đề cập đến phương thức của một giao diện chức năng. (Như đã đề cập, các giao diện chức năng có thể chỉ có một phương thức mỗi phương thức).
Một số ví dụ khác: accept
phương thức trong Người tiêu dùng nhận đầu vào nhưng không trả về bất cứ điều gì.
Consumer<Integer> b1 = System::exit; // void exit(int status)
Consumer<String[]> b2 = Arrays::sort; // void sort(Object[] a)
Consumer<String> b3 = MyProgram::main; // void main(String... args)
class Hey {
public double getRandom() {
return Math.random();
}
}
Callable<Double> call = hey::getRandom;
Supplier<Double> call2 = hey::getRandom;
DoubleSupplier sup = hey::getRandom;
// Supplier is functional interface that takes no argument and gives a result
Ở trên, getRandom
không có đối số và trả về a double
. Vì vậy, bất kỳ giao diện chức năng nào thỏa mãn các tiêu chí: không tranh luận và trả vềdouble
có thể được sử dụng.
Một vi dụ khac:
Set<String> set = new HashSet<>();
set.addAll(Arrays.asList("leo","bale","hanks"));
Predicate<String> pred = set::contains;
boolean exists = pred.test("leo");
Trong trường hợp các loại tham số :
class Param<T> {
T elem;
public T get() {
return elem;
}
public void set(T elem) {
this.elem = elem;
}
public static <E> E returnSame(E elem) {
return elem;
}
}
Supplier<Param<Integer>> obj = Param<Integer>::new;
Param<Integer> param = obj.get();
Consumer<Integer> c = param::set;
Supplier<Integer> s = param::get;
Function<String, String> func = Param::<String>returnSame;
Tham chiếu phương thức có thể có các kiểu khác nhau, nhưng về cơ bản, tất cả chúng đều có nghĩa giống nhau và có thể được hình dung đơn giản là lambdas:
- Một phương thức tĩnh (
ClassName::methName
)
- Một phương thức thể hiện của một đối tượng cụ thể (
instanceRef::methName
)
- Một siêu phương thức của một đối tượng cụ thể (
super::methName
)
- Một phương thức thể hiện của một đối tượng tùy ý thuộc một loại cụ thể (
ClassName::methName
)
- Một tham chiếu hàm tạo lớp (
ClassName::new
)
- Một tham chiếu hàm tạo (
TypeName[]::new
)
Để tham khảo thêm, hãy xem http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html .