2012-08-13 11 views
17

Mam metodę tak:Jak rzucić wyjątek, gdy podpis metody nie pozwala na wyrzucenie wyjątku?

public void getSomething(){ 
... 
} 

chcę rzucać Exception wewnątrz getSomething(). Kompilator nie pozwoli mi tego zrobić, ponieważ moja metoda nie pozwala na wrzucenie tam Exception. Ale muszę rzucić podklasę Exception dla mojego testowania (Nie mogę wyrzucić niezaznaczony Exception). To jest oczywiście hack, ale potrzebuję go do moich testów. Próbowałem EasyMock, ale to też nie pozwala mi tego robić. Wszelkie pomysły, jak to zrobić?

Dzięki, Sean Nguyen

+0

Testujemy, że coś jest niemożliwe stało. Czemu? – rodrigoap

+0

Próbowałem sfałszować odpowiedzi mydła przy użyciu LogicalHandler . W handleMessage (kontekście LogicalMessageContext) nie zadeklarowano wyjątków rzutów. Ale wszystkie wyjątki wyrzucane przez punkt końcowy mydła są podklasą wyjątków. Muszę rzucić ten wyjątek, aby sfałszować moją odpowiedź na usługi. –

+0

Zobacz moją edycję, jeśli jesteś zainteresowany. –

Odpowiedz

19

Metoda 1:

This post by Alexey Ragozin opisuje jak korzystać trick rodzajowych aby rzucić nierejestrowanej sprawdzony wyjątek. Od tego postu:

public class AnyThrow { 

    public static void throwUnchecked(Throwable e) { 
     AnyThrow.<RuntimeException>throwAny(e); 
    } 

    @SuppressWarnings("unchecked") 
    private static <E extends Throwable> void throwAny(Throwable e) throws E { 
     throw (E)e; 
    } 
} 

Sztuczka polega na throwUnchecked „leżący” do kompilatora, że ​​typ E jest RuntimeException z jego wywołaniu throwAny. Ponieważ throwAny jest zadeklarowany jako throws E, kompilator myśli, że konkretne połączenie może po prostu rzucić RuntimeException. Oczywiście sztuczka jest możliwa dzięki throwAny arbitralnie deklarując E i ślepo na nią rzucając, pozwalając dzwoniącemu zdecydować, do czego argument jest rzucony - straszny projekt podczas kodowania sanely. W czasie wykonywania, E jest erased i nie ma znaczenia.

Jak już zauważyłeś, robienie czegoś takiego to ogromny hack i powinieneś bardzo dobrze udokumentować jego użycie.


Metoda 2:

Można również użyć sun.misc.Unsafe do tego celu. Najpierw należy wdrożyć metodę, która wykorzystuje odbicia powrócić instancję tej klasy to:

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

Jest to konieczne, ponieważ wywołanie Unsafe.getUnsafe() zazwyczaj rzucać SecurityException. Gdy masz wystąpienie Unsafe można umieścić jej przerażające możliwości użycia:

Unsafe unsafe = getUnsafe(); 
unsafe.throwException(new Exception()); 

zasługa this answer na stanowisku https://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe.Pomyślałem, że wspomnę o tym dla kompletności, ale prawdopodobnie lepiej po prostu użyć powyższej sztuczki, zamiast pozwolić na wpisanie Unsafe do kodu.


Metoda 3:

w komentarzach połączonego odpowiedź na temat korzystania Unsafe, @bestsss points out znacznie prostszy sztuczka przy użyciu przestarzałej metody Thread.stop(Throwable):

Thread.currentThread().stop(new Exception()); 

W tym przypadku byś użyj @SuppressWarnings("deprecation") i jeszcze raz dokumentuj bardzo gwałtownie. Znowu wolę pierwszą sztuczkę dla jej (względnej) czystości.

+0

bardzo dziękuję. to działa! –

+0

@PaulBellora zawsze można grać za pomocą metody 'Class :: newInstance()', która może rzucić wszystko, co robi ctor – emesx

+0

@PaulBellora Dlaczego pierwszy przykład nie powoduje 'ClassCastException' w środowisku wykonawczym? – Demi

1

Java ma dwa rodzaje wyjątków, sprawdzone i niekontrolowany. Musisz zadeklarować sprawdzone wyjątki, ale nie musisz zadeklarować niezaznaczonych wyjątków.

RuntimeException to podstawowy niezaznaczony wyjątek, który można rzucać bez deklarowania.

public void getSomething(){ 
    throw new RuntimeException("I don't have to be declared in the method header!"); 
} 

Na marginesie, to prawdopodobnie nie chcą rzucać surowe RuntimeException, ale rozszerzyć ją na coś bardziej konkretnego do swoich potrzeb. Każda podklasa RuntimeException również nie będzie zaznaczona.

+0

Przykro mi z powodu braku jasności. Muszę rzucić podklasę java.lang.Exception (sprawdzony wyjątek). –

+3

@SeanNguyen RuntimeException jest podklasą wyjątku. Jest to po prostu szczególny przypadek w Javie, gdzie nie trzeba deklarować, że zostanie rzucony. – Oleksi

+0

Przepraszam, niezbyt wyraźnie. Muszę rzucić zaznaczone wyjątek, który jest subscass wyjątku. Nie mogę rzucić wyjątku RuntimeException. –

0

Nie wiem, co próbowaliście zrobić. Możesz po prostu rzucić niesprawdzony wyjątek wewnątrz swojej metody, a następnie przetestować używając JUnit, jak w poniższym przykładzie.

public void getSomething() { 
    throw new RuntimeException(); 
} 

JUnit Przykład 4 Test:

@Test 
public void testGetSomething() { 
    try { 
     getSomething(); 
     fail("Expecting RuntimeException!"); 
    } catch (Exception e) { 
     Logger.getLogger("test").info("Exception was caught: " + e.getClass()); 
    } 
} 
Powiązane problemy