2014-04-25 19 views
9

Tôi đang sử dụng một giao diện trông giống dọc theo dòng này:Có cách nào để biến giao diện hiện có thành giao diện chức năng không?

public interface ObjectListener { 
    public void objectAdded(Object o); 
    public void objectRemoved(Object o); 
} 

Và tôi hiện đang sử dụng một lớp vô danh để thực hiện giao diện, nhưng tôi không quan tâm đến một trong hai phương pháp. Một cái gì đó dọc theo dòng này:

someObject.addListener(new ObjectListener() { 

    @Override 
    public void objectAdded(Object o) { 
     doSomething(o); 
    } 

    @Override 
    public void objectRemoved(Object o) {} 
}); 

Bây giờ, tôi đã sử dụng các biểu thức lambda mới trong Java 8 bất cứ nơi nào tôi có thể, và tôi muốn sử dụng sự đơn giản được thêm vào trong một tình huống như thế này. Sau khi tất cả, tôi chỉ thực hiện một trong những phương pháp, nhưng vì có hai phương pháp trong giao diện, tôi không thể sử dụng nó trong một biểu thức lambda.

Có cách nào để tôi vượt qua giới hạn này không?

+0

Xem [câu trả lời này] (http://stackoverflow.com/questions/21833537/java-8-lambda-expressions-what-about-multiple-methods-in-nested-class/21851111#21851111)… – Holger

+0

+ 1 cho câu hỏi được xây dựng tốt. –

Trả lời

7

Để sử dụng lại giao diện hiện tại không phải là giao diện chức năng trong biểu thức lambda, bạn cũng phải sử dụng tính năng Java8 mới, các phương thức mặc định.

Trong trường hợp này, nếu bạn muốn sử dụng biểu thức lambda thay cho lớp ẩn danh, bạn sẽ phải làm như sau.

Trước tiên, bạn cần phải xác định lại ObjectListener như một giao diện mới:

public interface ObjectAddedListener extends ObjectListener { 
    @Override 
    default public void objectRemoved(Object o) {} 
} 

Chúng tôi chỉ đơn giản là thêm một thực hiện mặc định rỗng vào phương pháp mà chúng ta không quan tâm, mà rời khỏi phương pháp objectAdded() như phương pháp trừu tượng duy nhất trong giao diện.

Sau đó, bạn có thể sử dụng các loại mới thay cho bất kỳ ObjectListener, và vì chỉ có một phương pháp mà không có một thực hiện trong giao diện mới, bạn có thể sử dụng nó trong các biểu thức lambda, như vậy:

ObjectAddedListener listener = o -> doSomething(o); 
someObject.addListener(listener); 

Lưu ý rằng nếu bạn muốn sử dụng loại mới này trực tiếp trong phương pháp addListener() đầu tiên bạn sẽ cần phải cast biểu thức lambda như kiểu vừa được định nghĩa như sau:

someObject.addListener((ObjectAddedListener) o -> doSomething(o)); 
+0

Hoặc, nếu bạn có thể chỉnh sửa mã 'ObjectListener', bạn có thể chỉ cần thêm' {} 'làm nội dung của' objectRemoved() 'và đó là :) Không cần kế thừa và gõ. –

+0

Trong trường hợp này, 'ObjectListener' không phải là mã của tôi, do đó cần mở rộng giao diện. – Jazzer

+0

Giải pháp này chỉ thực tế cho mã nội bộ sẽ không bao giờ là một phần của API công khai được xuất và sẽ được duy trì bởi cùng một lập trình viên. Lý do là phương thức mặc định trong giao diện sẽ không gây ra lỗi thời gian biên dịch trong mã máy khách mà cố gắng thực hiện giao diện nhưng không thực hiện tất cả các phương thức. Đối với mã mà khách hàng sẽ truy cập, sẽ tốt hơn nếu tách các phương thức thành các định nghĩa giao diện riêng của chúng. – scottb

0

một thay thế cho refactoring một giao diện hiện đó không phải là một giao diện phương thức trừu tượng (SAM) duy nhất để cho phép sử dụng với các biểu thức lambda Java 8 là tách các phương thức thành các kiểu riêng của chúng. Điều này là thích hợp nhất nếu hầu hết các phương thức trong giao diện đều có khả năng sử dụng với lambdas.

Ví dụ: xem xét giao diện cho phép truy cập có lập trình vào đối tượng mô hình dữ liệu theo tên trường. Giao diện chứa một phương thức cho việc đọc các lĩnh vực và một cho đột biến trên sân:

interface Accessible { 
    Object acc(String fieldName); 
    void mut(String fieldName, Object val); 
} 

Dường như có thể, thậm chí có khả năng, mà cả những phương pháp này có thể được sử dụng với lambdas cho biểu cảm tốt hơn và đơn giản. Để đạt được điều này, giao diện có thể được refactored theo cách này (chỉ là một ví dụ, có một số cách để làm điều này):

class Accessors { 

    private Accessors() { throw new AssertionError(); } 

    interface Accessor { 
     Object acc(String fieldName); 
    } 

    interface Mutator { 
     void mut(String fieldName, Object val); 
    } 
} 

Lớp học mà cung cấp cả giờ đây đọc và viết truy cập vào các đối tượng mô hình dữ liệu sẽ cần phải triển khai cả hai Accessors.AccessorAccessors.Mutator. Quan trọng hơn, mặc dù, các giao diện này (hiện nay cả hai giao diện chức năng) có thể được sử dụng như các chiến lược cho phép sử dụng các biểu thức Java 8 Javada trong mã của bạn.

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