2013-02-22 12 views
16

Ogólnie rzecz biorąc, kompilator Java nie propaguje informacji, że metoda "zawsze" zgłasza wyjątek, a zatem nie wykrywa, że ​​wszystkie ścieżki kodu są kompletne .Czy można powiedzieć kompilatorowi, że metoda zawsze generuje wyjątek

(Wynika to z faktu, że kompilator Java kompiluje każdą klasę niezależnie).

To jest problem, gdy chcesz napisać coś takiego.

public class ErrorContext { 
    public void fatalISE(String message) { 
     String context = "gather lots of information about the context of the error"; 
     throw new IllegalStateException(context +": " + message); 
    } 
} 

public class A { 
    public MyObject myMethod() { 
     if (allIsGood()) { 
      return new MyObject(); 
     } 
     ErrorContext.fatalISE("all is not good"); 
    } 
} 

(tj. Rodzaj "pomocnika potwierdzającego", który zbiera informacje kontekstowe).

Ponieważ kompilator będzie narzekał, że myMethod nie zawsze zwraca obiekt MyObject.

Według mojej wiedzy nie ma adnotacji, która wskazywałaby, że metoda zawsze rzuca.

+1

roztworu w innym poście [tutaj] (http://stackoverflow.com/a/11249665/1402846). – Pang

Odpowiedz

30

Prostym rozwiązaniem jest pozwolić wasz nie metoda fatalISErzucać wyjątek, ale tylko go utworzyć:

public class ErrorContext { 
    public IllegalStateException fatalISE(String message) { 
     String context = "gather lots of information about the context of the error"; 
     return new IllegalStateException(context +": " + message); 
    } 
} 

public class A { 
    public MyObject myMethod() { 
     if (allIsGood()) { 
      return new MyObject(); 
     } 
     throw ErrorContext.fatalISE("all is not good"); 
    } 
} 

ten sposób kompilator będzie wiedział nie narzekać brakującym return. Zapomnienie o użyciu throw jest mało prawdopodobne, właśnie dlatego, że kompilator zwykle narzeka.

+6

Ma to * dużą * zaletę klarowności podczas czytania kodu. –

+0

czytelny, prosty i bezpieczny. Wspaniały ! – Zorglub

7

Sztuczka, że ​​używam jest zastąpienie

public void fatalISE(String message) { 
    String context = "gather lots of information about the context of the error"; 
    throw new IllegalStateException(context +": " + message); 
} 

z

public <T> T fatalISE(String message) { 
    String context = "gather lots of information about the context of the error"; 
    throw new IllegalStateException(context +": " + message); 
} 

Następnie w myMethod, użytkowania:

public MyObject myMethod() { 
    if (allIsGood()) { 
     return new MyObject(); 
    } 
    return ErrorContext.fatalISE("all is not good"); 
} 

To będzie działać niezależnie od typu zwracanej myMethod , w tym typy pierwotne. Wciąż możesz używać fatalISE w metodzie void, po prostu nie używając słowa kluczowego return.

+2

To jest sprytne (dość sprytne), ale nieco mylące dla osób czytających kod. –

+1

Wydaje się działać dla funkcji, które zwracają odwołania, ale nie dla elementów pierwotnych: 'parametry typu T nie można określić; nie istnieje unikalna maksymalna instancja dla zmiennej typu T z górnymi granicami int, java.lang.Object' na linii 'return this.fatalISE (" blah ");' –

5

dodać

return null; 

na końcu. (i tak nigdy nie dojdzie do tego, ale żeby uciszyć kompilator powinien to zrobić)

6

Co powiesz na cofnięcie warunku if?

public MyObject myMethod() { 
    if (!allIsGood()) { 
     ErrorContext.fatalISE("all is not good"); 
    } 
    return new MyObject(); 
} 

Powodzenia!

0

Właśnie natknąłem się na ten przypadek użycia, ale z metodą, która powinna zawsze wyrzucać 2 lub więcej typów wyjątków.

Aby kod został skompilowany, można dodać return null; jako MouseEvent.

lub lepiej zastąpić go throw new AssertionError() które uniemożliwiają powrót wartość null, poprawiają czytelność i upewnić się, że jeśli ktoś zmodyfikować checkAndAlwaysThrowException() wil nadal Zawsze rzutów wyjątkiem

public Object myMehtod() throws ExceptionType1, ExceptionType2 { 
    //.... 
    checkAndAlwaysThrowException(); 
    throw new AssertionError("checkAndAlwaysThrowException should have throw exception"); 
} 

public void checkAndAlwaysThrowException() throws ExceptionType1, ExceptionType2 { 
    if (cond) { 
     throw new ExceptionType1(); 
    } else { 
     throw new ExceptionType2(); 
    } 
} 
Powiązane problemy