Có cách nào để ném một ngoại lệ mà không cần thêm khai báo ném?


81

Tôi có một tình huống sau đây.

Tôi có một Lớp Java kế thừa từ một lớp cơ sở khác và ghi đè một phương thức. Phương thức cơ sở không ném ra các ngoại lệ và do đó không có throws ...khai báo.

Bây giờ phương pháp của riêng tôi sẽ có thể ném ngoại lệ nhưng tôi có thể lựa chọn

  • Nuốt ngoại lệ
  • Thêm một khai báo ném

Cả hai đều không thỏa mãn vì cái đầu tiên sẽ âm thầm bỏ qua ngoại lệ (ok, tôi có thể thực hiện một số ghi nhật ký) và cái thứ hai sẽ tạo ra lỗi trình biên dịch do các tiêu đề phương thức khác nhau.

public class ChildClass extends BaseClass {

        @Override 
        public void SomeMethod() {
            throw new Exception("Something went wrong");
        }
}

Câu trả lời:


99

Bạn có thể ném các ngoại lệ không được chọn mà không cần phải khai báo nếu bạn thực sự muốn. Các ngoại lệ không được kiểm tra mở rộng RuntimeException. Ném kéo dàiError cũng không được chọn, nhưng chỉ nên được sử dụng cho các vấn đề hoàn toàn không thể xử lý được (chẳng hạn như mã bytec không hợp lệ hoặc hết bộ nhớ).

Như một trường hợp cụ thể, Java 8 được thêm vào UncheckedIOExceptionđể gói và ném lại IOException.


1
Hoạt động tốt, tôi phải ném lại một RuntimeException vì ngoại lệ đến từ một phương thức khác nhưng nó hoạt động tốt, cảm ơn.
Jürgen Steinblock

42

Đây là một mẹo:

class Utils
{
    @SuppressWarnings("unchecked")
    private static <T extends Throwable> void throwException(Throwable exception, Object dummy) throws T
    {
        throw (T) exception;
    }

    public static void throwException(Throwable exception)
    {
        Utils.<RuntimeException>throwException(exception, null);
    }
}

public class Test
{
    public static void main(String[] args)
    {
        Utils.throwException(new Exception("This is an exception!"));
    }
}

Tôi tự hỏi nó hoạt động như thế nào? Tôi sẽ thực hiện một số nghiên cứu, nhưng bạn có tài nguyên nào có thể giúp tôi không? :-)
holmicz

T được suy ra là RuntimeException. Đã trả lời ở đây stackoverflow.com/questions/41380656/… và ở đây stackoverflow.com/questions/31316581/…
seenimurugan

1
Bí quyết tuyệt vời! Thủ thuật này cũng có thể áp dụng trên biểu thức / khối lambda, để cho phép gán phương thức ngoại lệ đã kiểm tra cho giao diện SAM mà không cần throwskhai báo.
JasonMing

có thêm tiền thưởng siêu bổ sung là không phải đối phó với sự không an toàn.
lscoughlin

Tại sao bạn cần tham số giả? Ngoài ra, điều này có thể hoạt động mà không có phương pháp chung?
Kiruahxh

28

Tùy chọn thứ ba là chọn không tham gia kiểm tra ngoại lệ (giống như bản thân API Chuẩn đôi khi phải thực hiện) và bọc ngoại lệ đã kiểm tra trong RuntimeException:

throw new RuntimeException(originalException);

Bạn có thể muốn sử dụng một lớp con cụ thể hơn của RuntimeException.


10

Tôi chỉ muốn thêm một câu trả lời thay thế, hoàn toàn là một FYI :

Có, có một cách để ném một ngoại lệ đã kiểm tra mà không cần thêm throwskhai báo, bằng cách sử dụng sun.misc.Unsafelớp. Điều này được mô tả trong bài đăng blog sau:

Ném một ngoại lệ đã kiểm tra từ một phương thức mà không khai báo nó

Mã mẫu:

public void someMethod() {
  //throw a checked exception without adding a "throws"
  getUnsafe().throwException(new IOException());
}

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);
  }
}

Tuy nhiên, điều này không được khuyến khích. Tốt hơn là nên đặt trong một ngoại lệ không được kiểm tra như được nêu trong một số câu trả lời khác.


3
Có một lý do họ gọi đó là lớp học Unsafe.
OrangeDog

4

Tại sao bạn không ném một ngoại lệ không được kiểm tra? Điều này không cần phải được khai báo.

Hai lựa chọn thay thế là

  • bọc với một ngoại lệ đã chọn với một ngoại lệ không được chọn.
  • không cho trình biên dịch biết bạn đang ném một ngoại lệ đã kiểm tra, ví dụ như Thread.currentThread (). stop (e);
  • Trong Java 6, bạn có thể ném lại ngoại lệ nếu có finalvà trình biên dịch biết những ngoại lệ đã kiểm tra nào mà bạn có thể đã bắt gặp.
  • Trong Java 7, bạn có thể ném lại một ngoại lệ nếu nó là ngoại lệ cuối cùng, tức là bạn không thay đổi nó trong mã.

Phần sau sẽ hữu ích hơn khi bạn ném một ngoại lệ kiểm tra trong mã của bạn và bắt nó trong mã gọi điện của bạn, nhưng các lớp ở giữa không biết gì về ngoại lệ.


Phương pháp thứ hai là tương tác. Nhưng hiện tại, gói ngoại lệ là thứ tôi cần.
Jürgen Steinblock


@OrangeDog, vì bạn đã đọc cái này, bạn có thể cho tôi biết sự khác biệt giữa việc sử dụng stop () trên luồng hiện tại và ném một ngoại lệ được bọc không. ;)
Peter Lawrey

"phương thức sau đây về mặt hành vi giống với hoạt động ném của Java, nhưng phá vỡ nỗ lực của trình biên dịch để đảm bảo rằng phương thức gọi đã khai báo tất cả các ngoại lệ được kiểm tra mà nó có thể ném". Làm thế nào để gói ngoại lệ tốt hơn?
Peter Lawrey

"Việc dừng một luồng sẽ khiến nó mở khóa tất cả các màn hình mà nó đã khóa. Nếu bất kỳ đối tượng nào được bảo vệ bởi các màn hình này trước đây ở trạng thái không nhất quán, thì các luồng khác giờ đây có thể xem các đối tượng này ở trạng thái không nhất quán. [...] các ngoại lệ không được chọn khác [...] người dùng không có cảnh báo rằng chương trình của họ có thể bị hỏng. "
OrangeDog

4

Có, có một lý do nhưng nó không được khuyến khích ở tất cả các bạn có thể sử dụng:

Gói không an toàn Java

getUnsafe().throwException(new IOException());

Phương pháp này ném ra ngoại lệ đã kiểm tra, nhưng mã của bạn không bị buộc phải bắt hoặc ném lại nó. Cũng giống như ngoại lệ thời gian chạy.


2

Dưới đây là một ví dụ để chặn các ngoại lệ đã kiểm tra và gói chúng trong một ngoại lệ không được kiểm tra:

public void someMethod() {
   try {
      doEvil();
   }
   catch (IOException e)
   {
       throw new RuntimeException(e);
   }
}

-1

bạn có thể bắt ngoại lệ với khối try- catch trong phương thức của bạn bị ghi đè. thì bạn không cần khai báo câu lệnh throws-.


2
chắc chắn, nhưng sau đó tôi sẽ nuốt ngoại lệ, đó là hoàn toàn ngược lại những gì tôi muốn đạt được;)
Jürgen Steinblock

-1

Bạn có thể sử dụng bất kỳ ngoại lệ nào bắt nguồn từ RuntimeException hoặc chính RuntimeException

hoặc là

sử dụng khối thử cho mã ném ngoại lệ và xử lý nó ở đó

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.