Kontrola, či trieda existuje v prostredí Java
1. Prehľad
Kontrola existencie triedy by mohla byť užitočná pri rozhodovaní, ktorú implementáciu rozhrania použiť. Táto technika sa bežne používa počas starších nastavení JDBC.
V tomto návode preskúmame nuansy používania Class.forName () skontrolovať existenciu triedy v triede Java.
2. Pomocou Class.forName ()
Môžeme skontrolovať existenciu triedy pomocou Java Reflection, konkrétne Class.forName (). Dokumentácia ukazuje, že a ClassNotFoundException bude vyhodené, ak triedu nebude možné lokalizovať.
2.1. Kedy očakávať ClassNotFoundException
Najprv si napíšme test, ktorý určite hodí ClassNotFoundException aby sme vedeli, že naše pozitívne testy sú bezpečné:
@Test (očakáva sa = ClassNotFoundException.class) public void givenNonExistingClass_whenUsingForName_thenClassNotFound () hodí ClassNotFoundException {Class.forName ("class.that.does.not.exist"); }
Takže sme dokázali, že trieda, ktorá neexistuje, bude hodiť a ClassNotFoundException. Poďme napísať test pre triedu, ktorá skutočne existuje:
@ Test public void givenExistingClass_whenUsingForName_thenNoException () hodí ClassNotFoundException {Class.forName ("java.lang.String"); }
Tieto testy to dokazujú bežiaci Class.forName () a nechytať a ClassNotFoundException je ekvivalentná so zadanou triedou existujúcou v triede cesty. Nie je to však celkom dokonalé riešenie kvôli vedľajším účinkom.
2.2. Vedľajší efekt: Inicializácia triedy
Je nevyhnutné zdôrazniť, že bez zadania nakladača triedy, Class.forName () musí spustiť statický inicializátor v požadovanej triede. To môže viesť k neočakávanému správaniu.
Na ilustráciu tohto správania vytvorme triedu, ktorá hodí a RuntimeException keď je vykonaný jeho statický inicializačný blok, aby sme okamžite vedeli, kedy je vykonaný:
verejná statická trieda InitializingClass {static {if (true) {// povoliť vyvolanie výnimky v statickom inicializačnom bloku throw new RuntimeException (); }}}
Môžeme vidieť z pre meno () dokumentáciu, ktorú hodí ExceptionInInitializerError ak zlyhá inicializácia vyvolaná touto metódou.
Poďme napísať test, ktorý bude očakávať ExceptionInInitializerError pri pokuse nájsť našu InitializingClass bez zadania nakladača triedy:
@Test (očakáva sa = ExceptionInInitializerError.class) public void givenInitializingClass_whenUsingForName_thenInitializationError () hodí ClassNotFoundException {Class.forName ("path.to.InitializingClass"); }
Pretože vykonávanie statického inicializačného bloku triedy je neviditeľným vedľajším účinkom, teraz vidíme, ako by to mohlo spôsobiť problémy s výkonom alebo dokonca chyby. Pozrime sa, ako preskočiť inicializáciu triedy.
3. Rozprávanie Class.forName () preskočiť inicializáciu
Našťastie pre nás existuje preťažená metóda forName (), ktorý prijíma načítavač triedy a či má byť vykonaná inicializácia triedy.
Podľa dokumentácie sú nasledujúce hovory rovnocenné:
Class.forName ("Foo") Class.forName ("Foo", true, this.getClass (). GetClassLoader ())
Zmenou pravda do nepravdivé, teraz môžeme napísať test, ktorý kontroluje existenciu nášho InitializingClassbez spustenia jeho statického inicializačného bloku:
@ Test public void givenInitializingClass_whenUsingForNameWithoutInitialization_thenNoException () hodí ClassNotFoundException {Class.forName ("path.to.InitializingClass", false, getClass (). GetClassLoader ()); }
4. Moduly Java 9
Pre projekty Java 9+ je tu tretie preťaženie Class.forName (), ktorá prijíma a Modul a a String názov triedy. Toto preťaženie predvolene nespúšťa inicializátor triedy. Tiež sa pozoruhodne vracia nulový keď požadovaná trieda neexistuje, skôr ako hádzanie a ClassNotFoundException.
5. Záver
V tomto krátkom tutoriáli sme odhalili vedľajší efekt inicializácie triedy pri používaní Class.forName () a zistili ste, že môžete použiť pre meno () aby k tomu nedošlo.
Zdrojový kód so všetkými príkladmi v tomto tutoriále nájdete na GitHub.