Mikor dobja a Java a nem bejelentett, dobható kivételt?
Most jelentettem be az újat Tanulj tavaszt tanfolyam, amelynek középpontjában az 5. tavasz és a tavaszi bakancs 2 alapjai állnak:
>> ELLENŐRIZZE A FOLYAMATOT1. Áttekintés
Ebben az oktatóanyagban meg fogjuk nézni, hogy mi okozza a Java-t a UndeclaredThrowableException kivétel.
Először egy kis elmélettel kezdünk. Ezután két valós példával megpróbáljuk jobban megérteni ennek a kivételnek a természetét.
2. A UndeclaredThrowableException
Elméletileg a Java dobni fog példányt UndeclaredThrowableException amikor megpróbálunk be nem jelentett bejelölt kivételt dobni. Vagyis nem deklaráltuk a bejelölt kivételt a dob záradékot, de ezt a kivételt a módszer törzsébe dobjuk.
Azt állíthatjuk, hogy ez lehetetlen, mivel a Java fordító fordítási hibával megakadályozza ezt. Például, ha megpróbálunk fordítani:
public void be nem jelentett () {dobja új IOException (); }
A Java fordító nem sikerül a következő üzenettel:
java: be nem jelentett kivétel java.io.IOException; el kell fogni vagy el kell dobni
Annak ellenére, hogy a be nem jelentett, bejelölt kivételek dobása nem fordulhat elő fordítási időben, mégis futási időben lehetséges. Vegyük például egy futásidejű proxy elfogását egy olyan módszerrel, amely nem vet ki kivételeket:
public void save (Object data) {// kihagyva}
Ha maga a proxy ellenőrzött kivételt dob, a hívó szemszögéből a mentés metódus dobja az ellenőrzött kivételt. A hívó valószínűleg nem tud semmit erről a proxyról, és hibáztatja a mentés erre a kivételre.
Ilyen körülmények között a Java beilleszti a tényleges ellenőrzött kivételt egy UndeclaredThrowableException és dobja a UndeclaredThrowableException helyette. Érdemes megemlíteni, hogy a UndeclaredThrowableException maga ellenőrizetlen kivétel.
Most, hogy eleget tudunk az elméletről, nézzünk meg néhány valós példát.
3. Java dinamikus proxy
Első példaként hozzunk létre egy futásidejű proxyt a java.util.List interfészt és lehallgatják a módszerhívásait. Először is meg kell valósítanunk a InvocationHandler felületet, és tegye oda az extra logikát:
public class ExceptionalInvocationHandler implementálja az InvocationHandler {@Orride public Object invoke (Object proxy, Method method, Object [] args) Throwable {if ("size" .equals (method.getName ())) {dob új SomeCheckedException ("Mindig sikertelen" dobást) ); } dob új RuntimeException (); }} public class SomeCheckedException kiterjeszti a Exception {public SomeCheckedException (String üzenet) {super (message); }}
Ez a proxy ellenőrzött kivételt dob, ha a proxy módszer az méret. Ellenkező esetben ellenőrizetlen kivételt dob.
Lássuk, hogyan kezeli a Java mindkét helyzetet. Először felhívjuk a List.size () módszer:
ClassLoader classLoader = getClass (). GetClassLoader (); InvocationHandler invocationHandler = new ExceptionalInvocationHandler (); Lista proxy = (Lista) Proxy.newProxyInstance (classLoader, új Class [] {List.class}, invocationHandler); assertThatThrownBy (proxy :: size) .isInstanceOf (UndeclaredThrowableException.class) .hasCauseInstanceOf (SomeCheckedException.class);
Amint a fentiekből látható, létrehozunk egy proxyt a Lista felületet, és hívja a méret módszer rajta. A proxy viszont elfogja a hívást, és dob egy ellenőrzött kivételt. Ezután a Java beburkolja ezt az ellenőrzött kivételt a UndeclaredThrowableException.Ez azért történik, mert valahogy bedobunk egy bejelölt kivételt anélkül, hogy deklarálnánk a metódus deklarációban.
Ha más módszert hívunk a Lista felület:
assertThatThrownBy (proxy :: isEmpty) .isInstanceOf (RuntimeException.class);
Mivel a proxy ellenőrizetlen kivételt dob, a Java hagyja, hogy a kivétel a jelenlegi állapotban terjedjen.
4. Tavaszi szempont
Ugyanez történik, amikor egy ellenőrzött kivételt dobunk a Tavaszi aspektusba, miközben a javasolt módszerek nem nyilatkoztak róluk. Kezdjük egy kommentárral:
@Target (ElementType.METHOD) @Retention (RetentionPolicy.RUNTIME) public @interface ThrowUndeclared {}
Most tanácsot adunk az ezzel a feljegyzéssel ellátott összes módszerre:
@Aspect @Component public class UndeclaredAspect {@Around ("@ annotation (undeclared)") public Object advisise (ProceedingJoinPoint pjp, ThrowUndeclared undeclared) dob Throwable {dob új SomeCheckedException ("AOP ellenőrzött kivétel"); }}
Alapvetően ez a tanács minden megjegyzéssel ellátott metódust megtesz az ellenőrzött kivétel eldöntésére, még akkor is, ha nem nyilvánítottak ilyen kivételt. Most hozzunk létre egy szolgáltatást:
@Service public class UndeclaredService {@ThrowUndeclared public void doSomething () {}}
Ha meghívjuk az annotált metódust, a Java dob egy példányt UndeclaredThrowableException kivétel:
@RunWith (SpringRunner.class) @SpringBootTest (class = UndeclaredApplication.class) public class UndeclaredThrowableExceptionIntegrationTest {@Autowired private UndeclaredService service; @Test public void givenAnAspect_whenCallingAdvisedMethod_thenShouldWrapTheException () {assertThatThrownBy (service :: doSomething) .isInstanceOf (UndeclaredThrowableException.class) .hasCauseInstanceOf (SomeChack) }}
Amint fentebb látható, a Java okként összefoglalja a tényleges kivételt, és a UndeclaredThrowableException kivétel helyett.
5. Következtetés
Ebben az oktatóanyagban azt láttuk, hogy mi okozza a Java-t a UndeclaredThrowableException kivétel.
Szokás szerint az összes példa elérhető a GitHubon.
Java alsó