2015-10-07 12 views
5

Tôi có một sự hiểu biết tốt về hàm lambda trong Lisp. Java dường như không có sự linh hoạt như Lisp. Làm thế nào để tôi phải suy nghĩ về lambdas trong Java? Với mã bên dưới, tôi có thể làm như thế nào?Làm thế nào để vượt qua và sử dụng một hàm lambda tùy ý như tham số

public class Draw { 
    GraphicsContext gc; 

    static void draw(double x, double y, double w, double h, boolean drawRect) { 
     if (drawRect) { 
      gc.fillRect(x, y, w, h); 
     } else { 
      gc.strokeRect(x, y, w, h); 
     } 
    } 

    // How do I do that? 
    static void drawWithLambda(double x, double y, double w, double h /**, lambda */) { 
     lambda(x, y, w, h); 
    } 

    public static void main(String[] args) { 
     draw(0, 0, 50, 50, false); // OK 
     drawWithLambda(0, 0, 50, 50, GraphicsContext::fillRect); // Ok? 
    } 
} 
+3

Vui lòng đọc bài viết này: http://stackoverflow.com/questions/13604703/how-do-i-define-a-method-which-takes-a-lambda-as-a-parameter-in-java-8 – PiotrSliwa

Trả lời

3

Bạn phải xác định kiểu của một giao diện chức năng mà lập luận lambda phương pháp thực hiện:

drawWithLambda(double x, double y, double w, double h, SomeFuncInterface lambda) { 
    lambda.someMethod (x, y, w, h); // someMethod is the single method that 
            // SomeFuncInterface implements 
} 

Để cho dòng này để làm việc

drawWithLambda(0, 0, 50, 50, GraphicsContext::fillRect); 

phương pháp fillRect của GraphicsContext phải tương thích với chữ ký của phương thức của giao diện chức năng SomeFuncInterface.

BTW, GraphicsContext::fillRect là tham chiếu phương thức, không phải là biểu thức lambda. Bạn có thể truyền các biểu thức lambda, các tham chiếu phương thức hoặc bất kỳ việc thực hiện nào khác của giao diện chức năng (cá thể lớp thông thường, cá thể lớp ẩn danh, v.v.).

+1

'GraphicsContext :: fillRect' sẽ không biên dịch bởi vì bạn không thể tạo tham chiếu tĩnh cho không phải st phương thức atic 'fillRect'. Bạn cần sử dụng 'gc :: fillRect' trong đó' gc' là một thể hiện của 'GraphicsContext'. – Tunaki

+1

@Tunaki Câu trả lời của tôi là chung chung. Tôi không quen thuộc với lớp 'GraphicsContext', vì vậy tôi không biết liệu' fillRect' có tĩnh hay không. – Eran

3

Lambda trong Java hoạt động kết hợp với khái niệm functional interface.

Ví dụ điển hình là Function. Function là một giao diện chức năng có phương thức chức năng, apply, là một phương thức lấy một đối số duy nhất và trả lại kết quả.

Bạn có thể tạo giao diện chức năng của riêng bạn, những người sẽ định nghĩa một phương pháp chức năng dùng 4 thông số và không có kiểu trả về, như thế này:

@FunctionalInterface 
interface RectangleDrawer { 
    void draw(double x, double y, double w, double h); 
} 

(Các FunctionalInterface chú thích là không thực sự cần thiết nhưng nó mang lại một rõ ràng ý định).

Sau đó, bạn có thể tạo một lambda tuân thủ hợp đồng của giao diện chức năng này. lambda syntax điển hình là (method arguments) -> (lambda body). Trong ví dụ này, nó sẽ là: (x, y, w, h) -> gc.fillRect(x, y, w, h). Điều này biên dịch bởi vì lambda tuyên bố 4 đối số và không có kiểu trả về, vì vậy nó có thể được biểu diễn như là phương thức chức năng của RectangleDrawer được xác định trước đó.

Bạn ví dụ sẽ trở thành:

static GraphicsContext gc; 

public static void main(String[] args) { 
    draw(0, 0, 50, 50, (x, y, w, h) -> gc.fillRect(x, y, w, h)); 
    draw(0, 0, 50, 50, (x, y, w, h) -> gc.strokeRect(x, y, w, h)); 
} 

static void draw(double x, double y, double w, double h, RectangleDrawer drawer) { 
    drawer.draw(x, y, w, h); 
} 

Trong trường hợp đặc biệt này, người ta có thể sử dụng một method reference để tạo ra các lambda, sử dụng :: điều hành, cho phép viết mã đơn giản hơn:

static GraphicsContext gc; 

public static void main(String[] args) { 
    draw(0, 0, 50, 50, gc::fillRect); 
    draw(0, 0, 50, 50, gc::strokeRect); 
} 

static void draw(double x, double y, double w, double h, RectangleDrawer drawer) { 
    drawer.draw(x, y, w, h); 
} 
+0

Cảm ơn bạn rất nhiều. Tôi nghĩ rằng tôi đã nhận nó. Đối với mọi chức năng tôi muốn chuyển như tham số, tôi habe để xác định am interface interface chỉ có một định nghĩa hàm với cùng chữ ký như hàm tôi muốn sử dụng. – user2407434

+1

@ user2407434 Bạn không phải luôn luôn định nghĩa một interace, bạn có thể sử dụng những cái đã có sẵn trong ['java.util.function'] (https://docs.oracle.com/javase/8/docs/ api/java/util/function/package-summary.html) gói. – Tunaki

Các vấn đề liên quan