2015-05-28 13 views
11

Chúng tôi hiện đang trong quá trình di chuyển một ứng dụng từ Java 7 sang Java 8. Sau khi khắc phục một số vấn đề biên dịch, tôi tình cờ gặp một vấn đề tương tự như câu hỏi sau: ClassCast Error: Java 7 vs Java 8.Làm thế nào để phát hiện các cuộc gọi phương thức không rõ ràng có thể gây ra một ClassCastException trong Java 8?

Nói tóm lại, đây là một mẫu mã cho thấy vấn đề này:

public class Test { 
    public static void main(String[] args) { 
     System.out.println(String.valueOf(getVal("xxx"))); // 7: prints the result, 8: Exception 
    } 

    @SuppressWarnings("unchecked") 
    public static <T> T getVal(String param) { 
     // do some computation based on param... 
     return (T) result; // actual return type only depends on param so the caller knows what to expect 
    } 
} 

Ý tưởng là chúng tôi sẽ đẩy mà người gọi biết kiểu mong đợi, và điều này sẽ tránh anh ta chuyển kiểu tường minh (tôi đừng nói đây là một ý hay ...). Trong rất nhiều trường hợp, người gọi chỉ mong đợi một Object vì vậy không có diễn viên tiềm ẩn nào cả.

Như đã nêu trong câu hỏi trên, ví dụ String.valueOf hoạt động tốt trong Java 7 vì không có suy luận kiểu, do đó, giả sử Object. Bây giờ trong Java 8, trình biên dịch chọn loại cụ thể nhất (ở đây char[]), gây ra một ClastCastException khi chạy.

Vấn đề là chúng tôi có khoảng 350 cuộc gọi của phương thức getVal này. Có cách nào để phát hiện các cuộc gọi phương thức quá tải sẽ khác nhau giữa Java 7 và Java 8 không? I.E. phát hiện khi trình biên dịch Java 8 sẽ chọn một phương thức khác với trình biên dịch Java 7.

+2

Chúng tôi đã có một phương pháp tương tự cũng được gọi trong hàng trăm địa điểm. Tôi đã thay thế nó bằng cách giới thiệu tham số 'Class clazz' bổ sung. Bằng cách này bạn có thể xử lý lỗi rõ ràng: trả về null hoặc ném một số ngoại lệ cụ thể hơn. Tôi chỉ làm điều này bằng tay chi tiêu như nửa giờ. Tôi khuyên bạn nên làm như vậy. Tôi không biết làm thế nào để tự động hóa nó, do đó điều này không đủ điều kiện như là một câu trả lời cho câu hỏi của bạn. –

+2

Có một câu trả lời đơn giản: * không chặn cảnh báo “không được kiểm tra” *. Họ đã nói với bạn rằng mã của bạn là sai. Nếu bạn muốn sửa mã của mình ngay bây giờ đã quá muộn, chỉ cần tìm kiếm các lần xuất hiện của '@SuppressWarnings (" không được kiểm tra ")'… – Holger

+0

@Holger Bạn có thể nói điều đó với đồng nghiệp của tôi khi thực hiện điều này trong năm 2011 không? ;-) Tôi đã biết nó là một ý tưởng tồi ở nơi đầu tiên (mặc dù không phải là xấu như bây giờ trong Java 8). Ngoài ra, không có '@ SuppressWarnings' trên phương thức gọi chính nó, nó chỉ trong khai báo' getVal'. Việc xóa chú thích này ở đây sẽ không hiển thị bất kỳ tập quán nào có vấn đề. –

Trả lời

2

Một lựa chọn tốt hơn sẽ là:

public class Test { 
    public static void main(String[] args) { 
     System.out.println(String.valueOf(getVal("xxx"))); // 7: prints the result, 8: Exception 
    } 

    @SuppressWarnings("unchecked") 
    public static <T> T getVal(T param) { 
     // do some computation based on param... 
     return param; // actual return type only depends on param so the caller knows what to expect 
    } 
} 

mà sẽ làm việc trong cả hai Java 7 và Java 8.

+0

Đây không phải là một thay thế vì bạn áp đặt kiểu trả về giống như tham số (trong trường hợp của tôi là một 'Chuỗi' và tôi không thể thay đổi điều đó). Ngoài ra, câu hỏi là để xác định các trường hợp các cuộc gọi phương thức quá tải khác nhau giữa Java 7 và 8, để tránh thay đổi tất cả chúng hoặc tìm kiếm chúng bằng tay. –

1

Cuối cùng giải pháp là thay đổi getVal() trở Object:

public static Object getVal(String param) { 
     // do some computation based on param... 
     return result; 
    } 

và thêm phương thức thứ hai cũng có lớp mong muốn làm tham số:

public static <T> T getVal(String param, Class<T> clazz) { 
     return clazz.cast(getVal(param)); 
    } 

sau đó sửa tất cả các sự cố biên dịch (nơi người gọi không mong đợi Object) bằng cách thêm thông số lớp thích hợp.

Việc thêm diễn viên cũng sẽ hoạt động nhưng sẽ gây ra nhiều cảnh báo cho các phôi vô điều kiện. Các diễn viên vô điều kiện thực sự vẫn còn đó (thông qua các thông số clazz), nhưng điều này cho phép dễ dàng xác định tất cả người gọi cần một diễn viên khi họ sử dụng phương pháp với 2 tham số.

Thêm vào đó - và điều này là rất cụ thể đối với trường hợp này - nó xuất hiện rằng param bản thân là thường là kết quả của một cuộc gọi phương thức trên một số TypedParam<T> nơi T là loại lợi nhuận kỳ vọng của getVal(), và đó cũng chứa lớp T.

tôi như vậy có thể thực hiện một phương pháp thuận tiện thêm:

public static <T> T getVal(TypedParam<T> param) { 
     return getVal(param.stringValue(), param.getValueClass()); 
    } 

và thay thế tất cả getVal(param.stringValue()) bằng cách chỉ getVal(param).

Giải pháp này không giải quyết được trường hợp chung-phát hiện các cuộc gọi phương pháp quá tải mà sẽ khác nhau giữa Java 7 và Java 8 - nhưng nó giải quyết nó cho các phương pháp mà được biết là gây ra vấn đề này. Và chúng tôi đã không tìm thấy nó ở nơi khác kể từ đó.

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