Czy istnieje sposób na zgłoszenie wyjątku bez dodawania deklaracji rzutów?

81

Mam następującą sytuację.

Mam klasę Java, która dziedziczy z innej klasy bazowej i przesłania metodę. Metoda podstawowa nie zgłasza wyjątków i dlatego nie ma throws ...deklaracji.

Teraz moja własna metoda powinna być w stanie zgłosić wyjątek, ale ja albo mam wybór

  • Połknij wyjątek
  • Dodaj deklarację rzutów

Oba nie są satysfakcjonujące, ponieważ pierwsza z nich po cichu zignorowałby wyjątek (ok, mógłbym wykonać trochę logowania), a druga wygenerowałaby błędy kompilatora z powodu różnych nagłówków metod.

public class ChildClass extends BaseClass {

        @Override 
        public void SomeMethod() {
            throw new Exception("Something went wrong");
        }
}
Jürgen Steinblock
źródło

Odpowiedzi:

99

Możesz rzucać niezaznaczone wyjątki bez konieczności ich deklarowania, jeśli naprawdę chcesz. Niezaznaczone wyjątki rozszerzają się RuntimeException. Nie Errorzaznacza się również elementów uruchamiających, które rozszerzają się, ale powinny być używane tylko w przypadku problemów, których nie można obsłużyć (takich jak nieprawidłowy kod bajtowy lub brak pamięci).

W szczególnym przypadku Java 8 została dodana UncheckedIOExceptiondo pakowania i ponownego przesyłania IOException.

OrangeDog
źródło
1
Działa świetnie, muszę ponownie zgłosić wyjątek RuntimeException, ponieważ wyjątek pochodzi z innej metody, ale działa świetnie, dzięki.
Jürgen Steinblock
42

Oto sztuczka:

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!"));
    }
}
Eng. Fouad
źródło
Zastanawiam się, jak to działa? Zrobię trochę badań, ale czy masz jakieś zasoby, które mogą mi pomóc? :-)
holmicz 22.11.2016
T wywnioskowane jako RuntimeException. Odpowiedział tutaj stackoverflow.com/questions/41380656/ ... a tutaj stackoverflow.com/questions/31316581/…
seenimurugan Grudnia
1
Niesamowita sztuczka! Ta sztuczka może również dotyczyć wyrażenia / bloku lambda, aby umożliwić przypisanie metody zaznaczonego wyjątku do interfejsu SAM bez żadnych throwsdeklaracji.
JasonMing
ma dodatkową super premię polegającą na tym, że nie ma do czynienia z niebezpiecznymi.
lscoughlin
Dlaczego potrzebujesz parametru dummy? Czy to mogłoby działać bez metody ogólnej?
Kiruahxh
28

Trzecią opcją jest rezygnacja ze sprawdzania wyjątków (tak jak czasami musi to robić samo standardowe API) i zawinięcie zaznaczonego wyjątku w RuntimeException :

throw new RuntimeException(originalException);

Możesz użyć bardziej szczegółowej podklasy RuntimeException.

Michael Borgwardt
źródło
10

Chcę tylko dodać alternatywną odpowiedź, czysto do Twojej wiadomości :

Tak, istnieje sposób na throwszgłoszenie sprawdzonego wyjątku bez dodawania deklaracji przy użyciu sun.misc.Unsafeklasy. Jest to opisane w następującym wpisie na blogu:

Zgłoś sprawdzony wyjątek z metody bez deklarowania go

Przykładowy kod:

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

Jednak nie jest to zalecane. Lepiej jest zawrzeć niezaznaczony wyjątek, jak opisano w niektórych innych odpowiedziach.

dogbane
źródło
3
Jest powód, dla którego nazywają tę klasę Unsafe.
OrangeDog
4

Dlaczego nie wyrzucisz niezaznaczonego wyjątku? Nie trzeba tego deklarować.

Istnieją dwie możliwości

  • zawijać z zaznaczonym wyjątkiem z niezaznaczonym.
  • nie pozwól kompilatorowi wiedzieć, że rzucasz sprawdzony wyjątek, np. Thread.currentThread (). stop (e);
  • W Javie 6 możesz ponownie zgłosić wyjątek, jeśli tak jest, finala kompilator wie, które sprawdzone wyjątki zostały przechwycone.
  • W Javie 7 możesz ponownie zgłosić wyjątek, jeśli jest faktycznie ostateczny, tj. Nie zmieniasz go w kodzie.

To później jest bardziej przydatne, gdy rzucasz wyjątek check w swoim kodzie i przechwytujesz go w kodzie wywołującym, ale warstwy pomiędzy nimi nie wiedzą nic o wyjątku.

Peter Lawrey
źródło
Druga metoda też jest interesująca. Ale w tej chwili zawijanie wyjątku jest dokładnie tym, czego potrzebuję.
Jürgen Steinblock
@OrangeDog, skoro to przeczytałeś, czy możesz mi powiedzieć, jaka jest różnica między użyciem funkcji stop () w bieżącym wątku a wyrzuceniem opakowanego wyjątku. ;)
Peter Lawrey
„Następująca metoda jest behawioralnie identyczna z operacją wyrzutu Javy, ale omija próby kompilatora, aby zagwarantować, że metoda wywołująca zadeklarowała wszystkie sprawdzone wyjątki, które może zgłosić”. Jak jest lepsze opakowanie wyjątku?
Peter Lawrey
„Zatrzymanie wątku powoduje odblokowanie wszystkich monitorów, które zostały zablokowane. Jeśli którykolwiek z obiektów wcześniej chronionych przez te monitory był w niespójnym stanie, inne wątki mogą teraz wyświetlać te obiekty w stanie niespójnym. [...] W przeciwieństwie do inne niezaznaczone wyjątki [...] użytkownik nie ma żadnego ostrzeżenia, że ​​jego program może być uszkodzony. "
OrangeDog
4

Tak, jest powód, ale w ogóle nie jest to zalecane, możesz użyć:

Niebezpieczny pakiet Java

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

Ta metoda zgłasza sprawdzony wyjątek, ale kod nie jest zmuszony do przechwytywania ani ponownego zgłaszania. Podobnie jak wyjątek czasu wykonywania.

Ahmad Al-Kurdi
źródło
2

Oto przykład przechwytywania zaznaczonych wyjątków i umieszczania ich w niezaznaczonym wyjątku:

public void someMethod() {
   try {
      doEvil();
   }
   catch (IOException e)
   {
       throw new RuntimeException(e);
   }
}
Jason S.
źródło
-1

możesz złapać wyjątek za pomocą bloku try-catch w swojej metodzie przesłoniętej. wtedy nie musisz deklarować instrukcji rzucania.

Erhan Bagdemir
źródło
2
jasne, ale wtedy przełknąłbym wyjątek, który jest dokładnie odwrotnością tego, co chcę osiągnąć;)
Jürgen Steinblock
-1

Możesz użyć dowolnego wyjątku pochodzącego z samego RuntimeException lub RuntimeException

lub

użyj bloku try-block dla kodu wyrzucającego wyjątki i obsłuż go tam

fmucar
źródło