2015-07-17 29 views
6

Tôi đang sử dụng bản phát hành dịch vụ Eclipse Luna 2 (4.4.2), Java 8 u51.Hàm tạo hàm Java 8 từ đối tượng templated

Tôi đang cố gắng tạo phương thức sẽ tạo ra các cá thể của đối tượng được truyền dựa trên tham số phương thức khác. Nguyên mẫu được đơn giản hóa để

public <T> T test(Object param, T instance) { 
    Constructor<?> constructor = instance.getClass().getConstructors()[0]; // I actually choose a proper constructor 

    // eclipse reports "Unhandled exception type InvocationTargetException" 
    Function<Object, Object> createFun = constructor::newInstance; 

    T result = (T) createFun.apply(param); 
    return result; 
} 

On line với các báo cáo thực Function khai Unhandled exception type InvocationTargetException biên dịch lỗi. Tôi cần số Function để sử dụng sau trong luồng.

Tôi đã cố gắng thêm các khối try/catch khác nhau, khai báo ném, nhưng không có lỗi nào sửa lỗi trình biên dịch này.

Làm cách nào để mã này hoạt động?

+1

Bạn nghĩ gì là lợi thế của 'Function' đường vòng qua chỉ đơn giản gọi 'newInstance' mục' Constructor'? – Holger

+0

@Holger Tôi đã sử dụng 'newInstance' trên' Constructor' trong luồng và nó tạo ra cùng một thông điệp, vì vậy tôi đã tạo một SSCE như thế này. Đường vòng hàm thực sự cần thiết để giữ một chuỗi 'stream()' tương đối có thể đọc được. – Dariusz

+1

Tôi hiểu. Vì vậy, nó đã được một chút đơn giản hóa về trường hợp sử dụng và một biểu thức lambda như assylias đã đề nghị nên làm việc. Nhưng điều tôi muốn biết bây giờ là, liệu thực sự có một yêu cầu khắt khe về kiểu kết quả là kiểu chính xác của 'instance' (có thể là một phân lớp của' T') hay không, nói cách khác là dùng đến Reflection thực sự cần thiết ... – Holger

Trả lời

11

Bạn không thể ném ngoại lệ đã kiểm tra từ lambda với loại mục tiêu Function vì phương pháp apply của nó không loại trừ ngoại lệ. Vì vậy, bạn cần phải làm cho nó thành một ngoại lệ được kiểm soát, ví dụ bằng cách gói nó:

Function<Object, Object> createFun = o -> { 
    try { 
    return constructor.newInstance(o); 
    } catch (InstantiationException | InvocationTargetException | IllegalAccessException e) { 
    throw new RuntimeException(e); 
    } 
}; 

Một cách khác là dẫn trình biên dịch để suy nghĩ đó là một ngoại lệ được kiểm soát, trong đó sản xuất một vết đống bụi vs tùy chọn ở trên:

Function<Object, Object> createFun = o -> { 
    try { 
    return constructor.newInstance(o); 
    } catch (InstantiationException | InvocationTargetException | IllegalAccessException e) { 
    return uncheck(e); 
    } 
}; 

với phương pháp hữu ích sau đây:

@SuppressWarnings("unchecked") 
public static <E extends Throwable, T> T uncheck(Throwable t) throws E { 
    throw ((E) t); 
} 
+3

Bạn có thể ném một ngoại lệ đã kiểm tra từ một lambda. Nhưng không phải từ một lambda mà là nghĩa vụ phải thực hiện chức năng, bởi vì chức năng.apply() không ném một ngoại lệ đã kiểm tra. –

+1

@JBNizet Có, cảm ơn. – assylias

+2

Bạn có thể thắt chặt phương thức 'uncheck' bằng cách giới thiệu một' 'bị ràng buộc, vì vậy bạn không phải làm bất kỳ loại cast nào. Bạn cũng có thể thực hiện cú ném bên trong phương thức 'uncheck'; không cần cho hai phương pháp khi bạn chỉ có thể ném vào một. – Makoto

4

Điều này là do phương pháp tham khảo là một phương pháp với các trường hợp ngoại lệ có tên trong các lỗi thời gian biên dịch. Phương thức trừu tượng đơn lẻ R apply(T t ) trong java.util.Function không loại trừ các ngoại lệ này. Vì vậy, có một sự không phù hợp giữa các loại chức năng của java.util.Function và loại phương pháp tham khảo của bạn.

Sử dụng một loại chức năng với một phương thức khớp hoạt động ... ví dụ:

interface MyFunction<T,R> { 
     /** 
     * Applies this function to the given argument. 
     * 
     * @param t the function argument 
     * @return the function result 
     */ 
     R apply(T t) throws Throwable; 

    } 

    public <T> T test(Object param, T instance) throws InstantiationException, IllegalAccessException, 
      IllegalArgumentException, InvocationTargetException { 
     Constructor<?> constructor = instance.getClass().getConstructors()[0]; // I actually choose a proper constructor 

     // eclipse reports "Unhandled exception type InvocationTargetException" 
      MyFunction<Object,Object> createFun = constructor::newInstance; 

     T result = (T) createFun.apply(param); 
     return result; 
    } 
Các vấn đề liên quan