Bevezetés a kódminőségi szabályokba a FindBugs és a PMD segítségével
1. Áttekintés
Ebben a cikkben kiemelünk néhány olyan fontos szabályt, amelyet a kódelemző eszközök mutatnak be, például a FindBugs, a PMD és a CheckStyle.
2. Ciklikus komplexitás
2.1. Mi a ciklikus komplexitás?
A kód összetettsége fontos, ugyanakkor nehezen mérhető mutató. A PMD szilárd szabálykészletet kínál a Kódméret-szabályok szakaszban. Ezeket a szabályokat a módszerek méretével és szerkezetének összetettségével kapcsolatos jogsértések felderítésére tervezték.
A CheckStyle arról ismert, hogy képes kódot elemezni a kódolási szabványok és a formázási szabályok alapján. Néhány összetettségi mutató kiszámításával azonban felismerheti az osztályok / módszerek tervezésének problémáit is.
Az egyik legfontosabb komplexitásmérés, amelyet mindkét eszköz tartalmaz, a CC (Cyclomatic Complexity).
A CC érték kiszámítható a program független végrehajtási útvonalainak számával.
Például a következő módszer 3 ciklikus komplexitást eredményez:
public void callInsurance (Járműjármű) {if (vehicle.isValid ()) {if (Autójármű példánya) {callCarInsurance (); } else {delegateInsurance (); }}}
A CC figyelembe veszi a feltételes utasítások és a többrészes logikai kifejezések fészkelését.
Általánosságban elmondható, hogy a CC-nél 11-nél magasabb értékű kódot nagyon összetettnek, de nehéz tesztelni és karbantartani.
A statikus elemző eszközök által használt néhány általános érték az alábbiakban látható:
- 1-4: alacsony összetettség - könnyen tesztelhető
- 5-7: mérsékelt komplexitás - tolerálható
- 8-10: nagy komplexitás - a refaktorálást figyelembe kell venni a tesztelés megkönnyítése érdekében
- 11 + nagyon bonyolult - nagyon nehéz tesztelni
A bonyolultsági szint a kód tesztelhetőségét is befolyásolja, minél magasabb a CC, annál nagyobb nehézséget jelent a vonatkozó tesztek végrehajtása. Valójában a ciklomatikus komplexitás értéke pontosan megmutatja a 100% -os elágazási lefedettség eléréséhez szükséges tesztesetek számát.
A folyamathoz tartozó grafikon callInsurance () módszer:
A lehetséges végrehajtási utak a következők:
- 0 => 3
- 0 => 1 => 3
- 0 => 2 => 3
Matematikailag a CC a következő egyszerű képlet segítségével számítható:
CC = E - N + 2P
- E: Az élek száma összesen
- N: A csomópontok teljes száma
- P: A kilépési pontok teljes száma
2.2. Hogyan csökkenthető a ciklikus komplexitás?
Lényegében kevésbé összetett kód megírása érdekében a fejlesztők hajlamosak különböző megközelítéseket használni, a helyzettől függően:
- Kerülje a hosszadalmas írást kapcsoló állítások tervezési minták felhasználásával, pl. az építő és a stratégiai minták jó jelöltek lehetnek a kódmérettel és a bonyolultsággal kapcsolatos kérdések kezelésére
- Írjon újrafelhasználható és bővíthető módszereket a kódstruktúra moduláris átalakításával és a Egyetlen felelősség elve
- Más PMD kódméret-szabályok betartása közvetlen hatással lehet a CC-re, például. túlzott metódushosszszabály, túl sok mező egy osztályban, túl sok paraméterlista egyetlen metódusban ... stb
Fontolóra veheti a kód méretével és összetettségével kapcsolatos elveket és mintákat is, pl. a KISS (Keep It Simple and Stupid) elv, és SZÁRAZ (Ne ismételje meg önmagát).
3. Kivételek kezelésének szabályai
Lehet, hogy a kivételekhez kapcsolódó hibák szokásosak, de némelyiket nagyon alulbecsülik, és azokat ki kell javítani, hogy elkerüljék a kritikus diszfunkciókat a gyártási kódban.
A PMD és a FindBugs mindkettőnek nagyon sok szabálya van a kivételekkel kapcsolatban. Íme a választásunk arról, hogy mi tekinthető kritikusnak egy Java programban a kivételek kezelésekor.
3.1. Ne dobja be a kivételt végül
Mint már tudhatod, a végül{} A Java blokk általában fájlok bezárására és erőforrások felszabadítására szolgál, más célokra történő felhasználása a kódszag.
Egy tipikus hibára hajlamos rutin kivételt dob a végül{} Blokk:
Karaktersorozat tartalma = null; próbáld ki a {String lowerCaseString = content.toLowerCase (); } végül {dobj új IOException (); }
Ez a módszer állítólag a NullPointerException, de meglepő módon dob egy IOException, amely félrevezetheti a hívási módszert a rossz kivétel kezelése érdekében.
3.2. Visszatérve a végül Blokk
A return utasítás használata a végül{} blokk lehet, hogy csak zavaró. Azért olyan fontos ez a szabály, mert valahányszor a kód kivételt vet, a Visszatérés nyilatkozat.
Például a következő kód hibátlanul fut:
Karaktersorozat tartalma = null; próbáld ki a {String lowerCaseString = content.toLowerCase (); } végül {visszatér; }
A NullPointerException még nem fogták el, mégis visszadobták a végül Blokk.
3.3. Nem sikerült bezárni az adatfolyamot a kivétel alapján
A folyamok bezárása az egyik fő oka annak, hogy a végül blokk, de ez nem egy triviális feladat, mint amilyennek látszik.
A következő kód két folyamot próbál bezárni a végül Blokk:
OutputStream outStream = null; OutputStream outStream2 = null; próbáld ki az {outStream = new FileOutputStream ("test1.txt") parancsot; outStream2 = új FileOutputStream ("test2.txt"); outStream.write (bájt); outStream2.write (bájt); } catch (IOException e) {e.printStackTrace (); } végül {próbáld ki {outStream.close (); outStream2.close (); } catch (IOException e) {// IOException kezelése}}
Ha a outStream.close () utasítás dob egy IOException, a outStream2.close () kihagyásra kerül.
Gyors megoldás egy külön try / catch blokk használata lenne a második adatfolyam bezárása:
végül {próbáld ki {outStream.close (); } catch (IOException e) {// IOException kezelése} try {outStream2.close (); } catch (IOException e) {// IOException kezelése}}
Ha szép utat szeretne elkerülni az egymást követő próbáld / fogd blokkolja az Apache commons IOUtils.closeQuiety metódusát, ez megkönnyíti a folyamok bezárását anélkül, hogy IOException.
5. Rossz gyakorlatok
5.1. Az osztály meghatározza az összehasonlítást () és az Object.equals () értéket használja
Amikor megvalósítja a összehasonlítani() módszerrel, ne felejtsd el ugyanezt a egyenlő () módszer, különben a kód által visszaadott eredmények zavaróak lehetnek:
Autóautó = új Autó (); Autókocsi2 = new Car (); if (car.equals (car2)) {logger.info ("Egyenlőek"); } else {logger.info ("Nem egyenlőek"); } if (car.compareTo (car2) == 0) {logger.info ("Egyenlőek"); } else {logger.info ("Nem egyenlőek"); }
Eredmény:
Nem egyenlőek Egyenlőek
A zűrzavarok eltávolítása érdekében ajánlatos megbizonyosodni erről Object.equals () végrehajtásakor soha nem hívják meg Hasonló, ehelyett meg kell próbálnia felülírni valami ilyesmivel:
logikai egyenlő (o objektum) {return összehasonlításTo (o) == 0; }
5.2. Lehetséges Null Pointer Dereference
NullPointerException (NPE) tekinthető a legelterjedtebbnek Kivétel Java programozásban, és a FindBugs panaszkodik a Null PointeD dereferenciájáról, hogy elkerülje a dobást.
Íme a legalapvetőbb példa az NPE dobására:
Autó autó = null; car.doSomething ();
A NPE-k elkerülésének legegyszerűbb módja a null-ellenőrzés:
Autó autó = null; if (autó! = null) {autó.doSomething (); }
A semmissé tett ellenőrzések elkerülhetik az NPE-ket, de széles körű használatuk esetén minden bizonnyal befolyásolják a kód olvashatóságát.
Tehát itt van néhány technika, amellyel elkerülhetők az NPE-k null-ellenőrzés nélkül:
- Kerülje a kulcsszót nulla kódolás közben: Ez a szabály egyszerű, kerülje a kulcsszó használatát nulla a változók inicializálásakor, vagy az értékek visszaadásakor
- Használat @Nem nulla és @Nullable annotációk
- Használat java.util.Opcionális
- Végezze el a Null Object Pattern-t
6. Következtetés
Ebben a cikkben áttekintettük a statikus elemző eszközök által észlelt néhány kritikus hibát, alapvető útmutatásokkal a feltárt problémák megfelelő kezelésére.
A következő linkek megtekintésével böngészhet az egyes szabályok teljes készletében: FindBugs, PMD.