2012-07-10 33 views
14

Theo mục 6.3.2 của JCIP:Tại sao không thể chạy() của Runnable throw Exceptions?

Runnable là một trừu tượng khá hạn chế; chạy không thể trả về một giá trị hoặc ném ngoại lệ đã kiểm tra.

run() không thể trả về giá trị vì loại trả về của nó bị vô hiệu nhưng tại sao nó không thể ném ngoại lệ đã kiểm tra?

+0

nếu bạn cần trả lại giá trị bạn nên sử dụng Giao diện có thể gọi trong ExecutorService –

+3

Err, bởi vì nó được khai báo không như vậy? – EJP

+0

@downvoter care để giải thích? – Inquisitive

Trả lời

21

Nó không thể ném ngoại lệ đã kiểm tra vì nó không được khai báo là ném ngoại lệ đã kiểm tra từ phiên bản đầu tiên và quá nguy hiểm để thay đổi nó.

Ban đầu Runnable chỉ được sử dụng trong gói Thread và giả định nhà phát triển muốn bắt tất cả các ngoại lệ đã kiểm tra và xử lý thay vì đăng nhập vào System.err.

Callable được thêm khi bạn có thể thêm các tác vụ riêng lẻ vào Executor nơi bạn có thể chụp kết quả theo số Future và bất kỳ ngoại lệ nào được ném.

Callable giờ đây cho phép bạn trả lại giá trị và tùy chọn khai báo ngoại lệ đã kiểm tra.

BTW: Một cách để bạn có thể nói rằng bạn không muốn trả lại hàng hoặc ném một ngoại lệ kiểm tra từ một callable là sử dụng cái gì đó như

Callable<Void> callable = new Callable<Void>() { 
    public Void call() { 
     // do something 
     return null; 
    } 
}; 
+1

"Quá nguy hiểm" = = sẽ phá vỡ khả năng tương thích cho hàng trăm nghìn chương trình hiện có. Đó là một "không không"! –

+0

@peter Có thể gọi chỉ cho biết lợi tức từ cuộc gọi là loại void? Nó có nói bất cứ điều gì ở tất cả các trường hợp ngoại lệ có thể được ném từ cuộc gọi()? – Inquisitive

+0

Thực tế là không có mệnh đề 'ném' nào không có ngoại lệ kiểm tra. Ngay cả khi cha mẹ khai báo 'ném ngoại lệ 'không có nghĩa là con phải. Tuy nhiên, nếu phụ huynh không "ném" ngoại lệ đã kiểm tra, đứa trẻ không thể ném ngoại lệ đã kiểm tra. –

4

run() không thể ném một ngoại lệ kiểm tra bởi vì nó không được khai báo. Bạn không thể ném ngoại lệ đã kiểm tra mà không khai báo chúng.

Bạn cũng không thể khai báo các ngoại lệ đã kiểm tra trên phương pháp ghi đè hoặc thực hiện một phương pháp khác không loại trừ ngoại lệ đó. Do đó, việc triển khai Runnable không thể đơn giản thêm các điều khoản throws vào việc triển khai run() của chúng.

+1

Điều đặc biệt khó hiểu là tài liệu hiện tại cho [invokeAndWait] (http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html#invokeAndWait%28java.lang.Runnable% 29) thảo luận về những gì xảy ra "nếu phương thức Runnable.run ném một ngoại lệ chưa được bắt". Tôi chắc rằng nhiều người đã đọc điều đó và vô cùng cố gắng tuyên bố một mệnh đề ngoại lệ cho việc ghi đè() của họ. –

2

ngoại lệ Bạn luôn có thể không an toàn ném kiểm tra:

import java.lang.reflect.Field; 
import sun.misc.Unsafe; 

public class UnsafeSample { 
    public void methodWithNoDeclaredExceptions() { 
     Unsafe unsafe = getUnsafe(); 
     unsafe.throwException(new Exception("this should be checked")); 
    } 

    private Unsafe getUnsafe() { 
     try { 
      Field field = Unsafe.class.getDeclaredField("theUnsafe"); 
      field.setAccessible(true); 
      return (Unsafe) field.get(null); 
     } catch(Exception e) { 
      throw new RuntimeException(e); 
     } 
    } 

    public static void main(String[] args) { 
     new UnsafeSample().methodWithNoDeclaredExceptions(); 
    } 
} 

Xem toàn bộ bài viết ở đây:

http://java.dzone.com/articles/throwing-undeclared-checked.

Một thay thế:

public class Test { 
    public static void main(String[] args) { 
     doThrow(new SQLException()); 
    } 

    public static void doThrow(Exception e) { 
     Test.<RuntimeException> doThrow0(e); 
    } 

    @SuppressWarnings("unchecked") 
    public static <E extends Exception> void doThrow0(Exception e) throws E { 
     throw (E) e; 
    } 
} 

này được đưa ra ở đây:

http://java.dzone.com/articles/throw-checked-exceptions

Nói xong, không làm điều đó! ;-)

+0

Brrrrrrr .... Đó là điều xấu ... – assylias

+0

@assylias: Trong nhiều cách, có –

+1

Bạn thậm chí không cần sử dụng 'Không an toàn'. Các trường hợp ngoại lệ được kiểm tra được ném từ một hàm tạo không có args sẽ thoát khỏi một cuộc gọi 'newInstance'. Tôi sẽ thêm một câu trả lời ... –

2

Nếu bạn nhìn vào Runnable Interface bạn thấy rằng phương pháp void run() không được khai báo là ném bất kỳ ngoại lệ đã chọn nào và lớp Thread của bạn triển khai Giao diện Runnable.

JLS nói rằng phương thức m1 không thể ném ngoại lệ nếu trong Giao diện/Siêu lớp, nó không được khai báo.

6

Đây không phải là câu trả lời cho câu hỏi. Thay vào đó, nó là một tiếp theo để Lukas Eder's answer, hiển thị một cách khác để buôn lậu một ngoại lệ đã kiểm tra vào một nơi mà nó không được phép tĩnh. Điều này dựa trên thực tế là nếu một hàm tạo không có đối số được gọi với newInstance, bất kỳ ngoại lệ nào được kiểm tra, nó sẽ thoát ra ngoài.

public class Thrower { 

    private static final ThreadLocal<Exception> toThrow = new ThreadLocal<Exception>(); 

    public static void throwUnsafely(Exception e) { 
     try { 
      toThrow.set(e); 
      Thrower.class.newInstance(); 
     } catch (InstantiationException f) { 
      throw new RuntimeException("unexpected exception while throwing expected exception", f); 
     } catch (IllegalAccessException f) { 
      throw new RuntimeException("unexpected exception while throwing expected exception", f); 
     } finally { 
      toThrow.remove(); 
     } 
    } 

    private Thrower() throws Exception { 
     throw toThrow.get(); 
    } 

} 

Đây là loại cổ điển thực sự là một chiếc mũ đen Java voodoo. Đừng bao giờ làm điều này. Ngoại trừ các bên gây ấn tượng với mọi người.

+1

oh đó là sai LOL – rogerdpack

1

Tôi nghĩ động lực đằng sau việc giữ khoảng trống chữ ký() trong Runnable là nó không có nghĩa là được gọi như các phương thức khác, thay vào đó nó được thiết kế để được trình lên lịch trình của CPU gọi. Nếu vậy, ai sẽ nhận được giá trị trả về của nó và ai sẽ xử lý ném ngoại lệ đã kiểm tra bằng cách này. UncaughtExceptionHandler xuất hiện trong Java 5.0 để xử lý các trường hợp ngoại lệ chưa được ném bởi một Thread. Khung công tác Executor lưu giá trị trả về hoặc ném ngoại lệ (wrapper trong ExecutionException) là trạng thái của một số đối tượng được chia sẻ qua các chủ đề (như thể hiện lớp bên ngoài) và purveys đối tượng invoker (người đang chạy trong một số chủ đề khác) của tương lai. get().

+1

Chính xác. Như những người khác nói, rõ ràng là câu trả lời bằng chữ là "run() không được khai báo để ném bất cứ thứ gì", nhưng tôi nghĩ câu hỏi thực sự là tại sao nó lại như vậy. Và câu trả lời là, run() có nghĩa là được gọi bởi một luồng, kết thúc hoặc trả về một pool sau khi run() trả về, vậy ai sẽ bắt nó? Do đó không bao giờ có trường hợp ném một ngoại lệ sẽ hữu ích. –

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