2015-01-04 14 views
14

Tôi tạo ra một chức năng để lọc với nhiều vị từ mà tôi thực hiện một logic AND cho họ:Các loại mục tiêu của biểu thức này phải là một giao diện chức năng

@SafeVarargs 
public static <T> Stream<T> filter(Stream<T> source, Predicate<T>... predicates) { 
    return source.filter(Arrays.stream(predicates).reduce(predicates[0], Predicate::and)); 
} 

Khi gọi:

filter(IntStream.range(0, 10).boxed(), x -> x % 2 != 0, x -> x%3 == 0).forEach(System.out::println); 

Nó hoạt động tốt và in 3 và 9. Tuy nhiên khi tôi vượt qua một vị từ đơn lẻ như:

filter(IntStream.range(0, 10).boxed(), x -> x % 2 != 0).forEach(System.out::println); 

Tôi nhận được lỗi biên dịch:

The target type of this expression must be a functional interface 

Tại sao điều này?

enter image description here Đối infos Tôi sử dụng Eclipse Luna phiên bản 1.

+0

Bạn có thể đăng thêm mã .... – Devavrata

+1

@Devavrat Mã khác về cái gì? Mọi thứ đã được đăng ... Chữ ký phương thức và nội dung + lời gọi tạo ra lỗi biên dịch. – user2336315

+3

Trình biên dịch có hoạt động trên dòng lệnh không? Tôi đã có thể chạy cả hai ví dụ của bạn trong IntelliJ 14.0.2 và có '3',' 9' và '1',' 3', '5',' 7', '9' tương ứng. Có vẻ như nó có thể là một vấn đề của Eclipse. – mkobit

Trả lời

7

Đây là trường hợp góc cho trình biên dịch. Để xác định liệu nó có nên áp dụng varargs gói các đối số vào một mảng hay chỉ đơn giản là vượt qua một mảng, nó cần phải biết kiểu của đối số cuối cùng, tuy nhiên, trong trường hợp biểu thức lambda nó cần chữ ký phương thức được gọi để xác định kiểu. Nhưng rõ ràng điều gì sẽ xảy ra khi biểu thức lambda không bao giờ có thể là một loại mảng và vì vậy, javac biên dịch nó mà không có vấn đề gì.

Một công việc xung quanh chấp nhận được sẽ là quá tải phương pháp:

@SafeVarargs 
public static <T> Stream<T> filter(Stream<T> source, Predicate<T>... predicates) { 
    return source.filter(
     Arrays.stream(predicates).reduce(predicates[0], Predicate::and)); 
} 
public static <T> Stream<T> filter(Stream<T> source, Predicate<T> predicate) { 
    return source.filter(predicate); 
} 

Đây sẽ là một một công việc xung quanh chấp nhận được vì nó không yêu cầu bất kỳ thay đổi nào trên mặt gọi điện thoại đồng thời nâng cao hiệu quả cho các đơn trường hợp -arg cùng một lúc.


Xin lưu ý rằng phương pháp varargs của bạn cho phép không đối số nhưng sẽ thất bại nếu được gọi theo cách đó. Vì vậy, bạn nên một trong hai, thêm một tình trạng quá tải:

public static <T> Stream<T> filter(Stream<T> source) { 
    return source; 
} 

hoặc làm phương pháp an toàn đối với trường hợp không lập luận:

@SafeVarargs 
public static <T> Stream<T> filter(Stream<T> source, Predicate<T>... predicates) { 
    return Arrays.stream(predicates).reduce(Predicate::and) 
       .map(source::filter).orElse(source); 
} 
2

Cả Netbeans và Eclipse có một số lỗi trong lĩnh vực phân tích cú pháp biểu thức lambda trong Java. Chúng đang dần dần được sửa chữa nhưng, cho đến khi chúng có, cách giải quyết tốt nhất mà tôi đã tìm thấy là: 1. khai báo các loại 2. Nếu điều đó không hiệu quả, hãy sử dụng khối 3. nếu điều đó không hiệu quả, hãy tạo một ẩn danh đối tượng thực hiện vị từ/hàm, v.v.

Điều này làm cho mã của bạn trở nên phức tạp hơn nhưng chúng cần thiết trong một số trường hợp.

0

Đôi khi Eclipse cần một ol tốt' sạch và tái thiết của tất cả các dự án và các vấn đề Đi đi.

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