Mbinu Bora kutoka “Effective Java (3rd Edition)”

Dondoo kutoka “Effective Java (3rd Edition) ” cha Joshua Bloch

1. Rudisha mikusanyiko au safu tupu, si null

Ikiwa mbinu inarudisha Set, usiandike return null; kwa matokeo matupu – badala yake andika return Set.of();.

2. Fikiria mbinu tuli za kiwanda (static factory methods) badala ya constructors

public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}

Si bora kila mara, lakini katika baadhi ya matumizi zina faida nyingi:

Hasara:

3. Fikiria builder unapokabiliwa na vigezo vingi vya constructor

Viwanda tuli na constructors vina kikwazo kimoja kwa pamoja: havifai vizuri idadi kubwa ya vigezo vya hiari. Tatizo hili liliathiri sana baadhi ya miradi niliyoifanyia kazi.

4. Lazimisha sifa ya singleton kwa constructor ya faragha au aina ya enum

Chochote kisichohitaji mifano (instances) mingi kinapaswa kuundwa mara moja tu – iwe kwa @ApplicationScoped au kwa mtindo mwingine wa singleton.

5. Zuia uundaji wa mifano kwa constructor ya faragha

Mara kwa mara utataka kuandika darasa ambalo ni mkusanyiko tu wa mbinu tuli na sehemu tuli. Madarasa kama hayo yamepata sifa mbaya kwa sababu baadhi ya watu huyatumia vibaya ili kuepuka kufikiri kwa mtazamo wa vitu, lakini yana matumizi halali.

private MyStaticClass() {
    // private constructor to prevent instantiation
}

6. Epuka kuunda vitu visivyo vya lazima

String s = new String("bikini");  // DON'T DO THIS!

Au:

// Hideously slow! Can you spot the object creation?
private static long sum() {
    Long sum = 0L;
    for (long i = 0; i <= Integer.MAX_VALUE; i++)
        sum += i;
    return sum;
}

Suluhisho: Programu hii inatoa jibu sahihi, lakini ni ya polepole sana kuliko inavyopaswa, kwa sababu ya kosa la uchapaji la herufi moja. Kigeu sum kimetangazwa kama Long badala ya long, maana yake programu inaunda takriban mifano 2^31 isiyo ya lazima ya Long (takriban mmoja kwa kila mara long i inapoongezwa kwenye Long sum).

7. Epuka finalizers na cleaners

Finalizers hazitabiriki, mara nyingi ni hatari, na kwa ujumla hazihitajiki. Kuzitumia kunaweza kusababisha tabia isiyo thabiti, utendaji duni na matatizo ya kuhamishika kwa programu.

8. Pendelea try-with-resources kuliko try-finally

// try-with-resources - the best way to close resources!
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
}

9. Fikiria kutekeleza Comparable

Kwa kutekeleza Comparable, unaliwezesha darasa lako kufanya kazi pamoja na algoriti zote za kijenerikia na utekelezaji wa mikusanyiko unaotegemea kiolesura hiki.

10. Punguza ufikiaji wa madarasa na wanachama wake

Jambo muhimu zaidi kuliko yote linalotofautisha kipengele kilichoundwa vizuri na kilichoundwa vibaya ni kiwango ambacho kipengele hicho kinaficha data yake ya ndani na maelezo mengine ya utekelezaji kutoka kwa vipengele vingine. Kipengele kilichoundwa vizuri huficha maelezo yake yote ya utekelezaji, na kutenganisha API yake na utekelezaji wake kwa usafi. Kisha vipengele huwasiliana kupitia API zao tu na havijui jinsi kila kimoja kinavyofanya kazi ndani. Dhana hii, inayojulikana kama kuficha taarifa au ukapsuli (encapsulation), ni msingi mkuu wa usanifu wa programu.

11. Katika madarasa ya public, tumia mbinu za kufikia, si sehemu za public

Mara kwa mara unaweza kushawishika kuandika madarasa duni yasiyo na kazi nyingine zaidi ya kukusanya sehemu za mfano:

// Degenerate classes like this should not be public!
class Point {
    public double x;
    public double y;
}

Kwa kuwa sehemu za data za madarasa kama haya hufikiwa moja kwa moja, madarasa haya hayatoi faida za ukapsuli. Huwezi kubadilisha uwakilishi bila kubadilisha API, huwezi kulazimisha masharti yasiyobadilika (invariants), na huwezi kuchukua hatua ya ziada sehemu inapofikiwa. Watayarishaji programu wenye msimamo mkali wa kulenga vitu wanaona madarasa kama haya kuwa chukizo, na kwamba yanapaswa kubadilishwa kila mara na madarasa yenye sehemu za private na mbinu za kufikia za public (getters) na, kwa madarasa yanayobadilika, mbinu za kubadilisha (setters):

// Encapsulation of data by accessor methods and mutators
class Point {

    private double x;
    private double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() { return x; }
    public double getY() { return y; }

    public void setX(double x) { this.x = x; }
    public void setY(double y) { this.y = y; }
}

Bila shaka, wenye msimamo mkali wako sahihi linapokuja suala la madarasa ya public: ikiwa darasa linafikiwa nje ya kifurushi chake, toa mbinu za kufikia ili kuhifadhi unyumbufu wa kubadilisha uwakilishi wa ndani wa darasa. Ikiwa darasa la public linaweka wazi sehemu zake za data, matumaini yote ya kubadilisha uwakilishi wake yanapotea, kwa sababu msimbo wa wateja unaweza kuwa umesambaa kila mahali.

Hata hivyo, ikiwa darasa ni package-private au ni darasa la ndani la faragha, hakuna ubaya wowote wa asili kuweka wazi sehemu zake za data – ikizingatiwa kwamba zinaeleza ipasavyo dhana inayotolewa na darasa hilo.

12. Punguza ubadilikaji

Darasa lisilobadilika (immutable) ni darasa tu ambalo mifano yake haiwezi kubadilishwa. Taarifa zote zilizomo katika kila mfano hazibadiliki katika maisha yote ya kitu, kwa hiyo hakuna mabadiliko yanayoweza kuonekana kamwe. Maktaba za jukwaa la Java zina madarasa mengi yasiyobadilika, yakiwemo String, madarasa ya primitive yaliyofungashwa (boxed), pamoja na BigInteger na BigDecimal. Kuna sababu nyingi nzuri za hili: madarasa yasiyobadilika ni rahisi kubuni, kutekeleza na kutumia kuliko madarasa yanayobadilika. Hayaelekei sana kwenye makosa na ni salama zaidi. Ili kufanya darasa lisibadilike, fuata kanuni hizi tano:

  1. Usitoe mbinu zinazobadilisha hali ya kitu (zinazojulikana kama mutators).
  2. Hakikisha darasa haliwezi kupanuliwa. Hii inazuia madarasa madogo ya kizembe au yenye nia mbaya kuharibu tabia ya kutobadilika ya darasa kwa kutenda kana kwamba hali ya kitu imebadilika. Kuzuia urithi kwa kawaida hufanywa kwa kulifanya darasa kuwa final, kwa mfano.
  3. Fanya sehemu zote ziwe final. Hii inaeleza nia yako waziwazi kwa namna inayolazimishwa na mfumo. Pia, ni muhimu kuhakikisha tabia sahihi ikiwa rejea ya mfano mpya iliyoundwa inapitishwa kutoka thread moja hadi nyingine bila ulandanishi (synchronization), kama ilivyoelezwa katika modeli ya kumbukumbu.
  4. Fanya sehemu zote ziwe private. Hii inazuia wateja kupata ufikiaji wa vitu vinavyobadilika vinavyorejelewa na sehemu na kuvibadilisha moja kwa moja. Ingawa kitaalamu inaruhusiwa madarasa yasiyobadilika kuwa na sehemu za public final zenye thamani za primitive au rejea za vitu visivyobadilika, haipendekezwi kwa sababu inazuia kubadilisha uwakilishi wa ndani katika toleo la baadaye.
  5. Hakikisha ufikiaji wa kipekee kwa vipengele vyovyote vinavyobadilika. Ikiwa darasa lako lina sehemu zinazorejelea vitu vinavyobadilika, hakikisha wateja wa darasa hawawezi kupata rejea za vitu hivyo. Kamwe usianzishe sehemu kama hiyo kwa rejea ya kitu iliyotolewa na mteja, wala usirudishe sehemu hiyo kutoka kwa mbinu ya kufikia. Tengeneza nakala za kujihami katika constructors, mbinu za kufikia na mbinu za readObject.

13. Pendelea utunzi kuliko urithi

Urithi ni njia yenye nguvu ya kutumia msimbo tena, lakini si mara zote chombo bora kwa kazi hiyo. Ukitumiwa isivyofaa, husababisha programu dhaifu. Ni salama kutumia urithi ndani ya kifurushi, ambapo utekelezaji wa darasa dogo na darasa kuu uko chini ya udhibiti wa watayarishaji programu walewale. Pia ni salama kutumia urithi unapopanua madarasa yaliyoundwa na kuandikiwa nyaraka mahususi kwa ajili ya kupanuliwa. Hata hivyo, kurithi kutoka kwa madarasa ya kawaida halisi (concrete) kuvuka mipaka ya vifurushi ni hatari.

Tofauti na kuita mbinu, urithi unavunja ukapsuli. Unaweza kufikiri ni salama kupanua darasa ikiwa unaongeza tu mbinu mpya na kujizuia kubatilisha (override) mbinu zilizopo. Ingawa upanuzi wa aina hii ni salama zaidi, hauna uhakika kamili. Ikiwa darasa kuu litapata mbinu mpya katika toleo linalofuata, na kwa bahati mbaya ulikuwa umelipa darasa dogo mbinu yenye saini ileile lakini aina tofauti ya kurudisha, darasa lako dogo halitakusanywa tena. Ikiwa umelipa darasa dogo mbinu yenye saini na aina ya kurudisha sawa na mbinu mpya ya darasa kuu, basi sasa unaibatilisha, kwa hiyo unakabiliwa na matatizo yaliyoelezwa awali. Zaidi ya hayo, ni shaka kama mbinu yako itatimiza mkataba wa mbinu mpya ya darasa kuu, kwa sababu mkataba huo ulikuwa bado haujaandikwa ulipoandika mbinu ya darasa dogo.

Kwa bahati nzuri, kuna njia ya kuepuka matatizo yote yaliyoelezwa hapo juu. Badala ya kupanua darasa lililopo, lipe darasa lako jipya sehemu ya private inayorejelea mfano wa darasa lililopo. Muundo huu unaitwa utunzi (composition) kwa sababu darasa lililopo linakuwa kipengele cha darasa jipya. Kila mbinu ya mfano katika darasa jipya inaita mbinu inayolingana kwenye mfano uliomo wa darasa lililopo na kurudisha matokeo. Hii inajulikana kama upelekaji (forwarding), na mbinu katika darasa jipya zinajulikana kama mbinu za kupeleka. Darasa linalotokana litakuwa imara kabisa, bila utegemezi wowote kwa maelezo ya utekelezaji wa darasa lililopo. Hata kuongeza mbinu mpya kwenye darasa lililopo hakutakuwa na athari yoyote kwa darasa jipya.

14. Pendelea violesura kuliko madarasa dhahania

Java ina njia mbili za kufafanua aina inayoruhusu utekelezaji mwingi: violesura na madarasa dhahania. Tangu mbinu chaguo-msingi (default methods) za violesura zilipoanzishwa katika Java 8, njia zote mbili zinakuwezesha kutoa utekelezaji wa baadhi ya mbinu za mfano.

Tofauti kubwa ni kwamba, ili kutekeleza aina iliyofafanuliwa na darasa dhahania, darasa lazima liwe darasa dogo la darasa hilo dhahania. Kwa kuwa Java inaruhusu urithi mmoja tu, kizuizi hiki kwa madarasa dhahania kinapunguza sana matumizi yake kama ufafanuzi wa aina. Darasa lolote linalofafanua mbinu zote zinazohitajika na kutii mkataba wa jumla linaruhusiwa kutekeleza kiolesura, bila kujali darasa hilo liko wapi katika daraja la madarasa. Madarasa yaliyopo yanaweza kurekebishwa kwa urahisi ili kutekeleza kiolesura kipya.

15. Generics: Usitumie aina ghafi (raw types)

Hugundui kosa hadi wakati wa kuendesha programu, muda mrefu baada ya kutokea, na katika msimbo ambao huenda uko mbali na msimbo wenye kosa. Ukishaona ClassCastException, lazima utafute katika msimbo wote ili kupata mwito wa mbinu ulioweka sarafu ndani ya mkusanyiko wa stempu. Kikusanyaji (compiler) hakiwezi kukusaidia.

16. Generics: Ondoa maonyo ya unchecked

Unapoandika programu kwa generics, utaona maonyo mengi ya kikusanyaji:

Kadiri unavyopata uzoefu zaidi na generics, ndivyo utakavyopata maonyo machache, lakini usitarajie msimbo mpya kukusanywa bila onyo lolote. Maonyo mengi ya unchecked ni rahisi kuondoa. Kwa mfano, tuseme kwa bahati mbaya umeandika tangazo hili:

Set<Lark> exaltation = new HashSet();

Libadilishe kuwa:

Set<Lark> exaltation = new HashSet<>();

Baadhi ya maonyo yatakuwa magumu zaidi sana kuondoa. Unapopata maonyo yanayohitaji kufikiri, vumilia! Ondoa kila onyo la unchecked unaloweza kuondoa.

Ukiondoa maonyo yote, una uhakika kwamba msimbo wako ni salama kiaina (typesafe), na hilo ni jambo zuri sana. Inamaanisha hutapata ClassCastException wakati wa kuendesha, na inaongeza imani yako kwamba programu yako itatenda kama ulivyokusudia. Ikiwa huwezi kuondoa onyo, lakini unaweza kuthibitisha kwamba msimbo uliosababisha onyo ni typesafe, basi (na hapo tu) zima onyo hilo kwa annotation ya @SuppressWarnings("unchecked"). Ukizima maonyo bila kwanza kuthibitisha kwamba msimbo ni typesafe, unajipa hisia za uongo za usalama. Msimbo unaweza kukusanywa bila kutoa onyo lolote, lakini bado unaweza kurusha ClassCastException wakati wa kuendesha.

Kila unapotumia annotation ya @SuppressWarnings("unchecked"), ongeza maoni yanayoeleza kwa nini ni salama kufanya hivyo.

17. Generics: Pale zinapoleta maana

Lo – darasa linalohitaji generics kwa dharura:

Mfano wa darasa linalohitaji generics

Kitu kama hiki kinapaswa kunaswa kabla ya merge request kukubaliwa, si baadaye!

18. Generics: Jinsi ya kutofanya

Samahani, hakuna haja ya maneno. Tafadhali KAMWE usiunganishe (merge) hiki:

public abstract class JpaLearningCardBaseContentService<LC extends LearningCardBaseContent<L, LC, AC>, J extends JpaLearningCardBaseContent<L, LC, AC>, L extends
        LearningCardBase<LC, A>, A extends AnswerOptionBase<L, AC>, AC extends AnswerOptionBaseContent<LC, AC, A>, AS extends AnswerOptionBaseService<A, AC, L, LC>, ACS extends
        AnswerOptionBaseContentService<AC, A, L, LC>, LS extends LearningCardBaseService<L>>
    extends JpaLightPersistenceService<LC, J, Long> implements LearningCardBaseContentService<LC, L, A, AC> {
    // ...
}

Tangazo la darasa peke yake halipaswi kamwe kuchukua dakika 5 kulielewa.

19. Pendelea orodha kuliko safu

Safu (arrays) zinatofautiana na aina za generics kwa njia mbili muhimu. Kwanza, safu ni covariant. Neno hili linalotisha linamaanisha tu kwamba ikiwa Sub ni aina ndogo ya Super, basi aina ya safu Sub[] ni aina ndogo ya aina ya safu Super[]. Kinyume chake, generics ni invariant: kwa aina mbili zozote tofauti Type1 na Type2, List<Type1> si aina ndogo wala aina kuu ya List<Type2>.

20. Pendelea lambda kuliko madarasa yasiyo na jina

// Anonymous class instance as a function object - obsolete!
Collections.sort(words, new Comparator<String>() {
    public int compare(String s1, String s2) {
        return Integer.compare(s1.length(), s2.length());
    }
});

Badala yake, fanya hivi:

// Lambda expression as function object (replaces anonymous class)
Collections.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length()));

21. Punguza upeo wa vigeu vya ndani

Mbinu yenye nguvu zaidi ya kupunguza upeo wa kigeu cha ndani ni kukitangaza pale kinapotumika kwa mara ya kwanza...

22. Pendelea vitanzi vya for-each kuliko vitanzi vya kawaida vya for

// The preferred idiom for iterating over collections and arrays
for (Element e : elements) {
    ... // Do something with e
}

23. Zijue na uzitumie maktaba

Tuseme unataka kuzalisha namba kamili nasibu kati ya sifuri na kikomo fulani cha juu. Wakikabiliwa na kazi hii ya kawaida, watayarishaji programu wengi wangeandika mbinu ndogo inayofanana na hii:

// Common but deeply flawed!
static Random rnd = new Random();

static int random(int n) {
    return Math.abs(rnd.nextInt()) % n;
}

Mbinu hii inaweza kuonekana nzuri, lakini ina kasoro tatu. Ya kwanza ni kwamba ikiwa n ni kipeo kidogo cha mbili, mfuatano wa namba nasibu utajirudia baada ya kipindi kifupi kiasi. Kasoro ya pili ni kwamba ikiwa n si kipeo cha mbili, baadhi ya namba, kwa wastani, zitarudishwa mara nyingi zaidi kuliko nyingine. Ikiwa n ni kubwa, athari hii inaweza kuwa dhahiri kabisa.

Kasoro ya tatu ya mbinu ya random ni kwamba inaweza, mara chache, kushindwa vibaya sana, na kurudisha namba iliyo nje ya masafa yaliyobainishwa. Hii ni kwa sababu mbinu inajaribu kuoanisha thamani inayorudishwa na rnd.nextInt() na int isiyo hasi kwa kuita Math.abs. Ikiwa nextInt() inarudisha Integer.MIN_VALUE, basi Math.abs pia itarudisha Integer.MIN_VALUE, na kiendeshaji cha baki (%) kitarudisha namba hasi, ikizingatiwa kwamba n si kipeo cha mbili. Hili karibu hakika litasababisha programu yako kushindwa, na kushindwa huko kunaweza kuwa vigumu kurudiwa.

24. Epuka float na double ikiwa majibu kamili yanahitajika

Tumia BigDecimal kwa kiasi cha fedha. float na double huzalisha makosa ya kukadiria.

Kwa mfano, tuseme una $1.03 mfukoni, na unatumia senti 42. Umebakiwa na pesa kiasi gani? Hiki ni kipande cha programu kisicho makini kinachojaribu kujibu swali hili:

System.out.println(1.03 - 0.42);

Kwa bahati mbaya, kinachapisha 0.6100000000000001. Hili si tukio la pekee. Tuseme una dola moja mfukoni, na unanunua vioshi (washers) tisa vinavyouzwa senti kumi kila kimoja. Utapata chenji kiasi gani?

System.out.println(1.00 - 9 * 0.10);

Kulingana na kipande hiki cha programu, unapata $0.09999999999999998.

Unaweza kufikiri tatizo linaweza kutatuliwa kwa kukadiria tu matokeo kabla ya kuyachapisha, lakini kwa bahati mbaya, hili halifanyi kazi kila mara. Kwa mfano, tuseme una dola moja mfukoni, na unaona rafu yenye safu ya peremende tamu zenye bei ya senti 10, 20, 30 na kuendelea, hadi dola moja. Unanunua peremende moja ya kila aina, kuanzia ile ya senti 10, hadi unaposhindwa kumudu peremende inayofuata kwenye rafu.

25. Pendelea aina za primitive kuliko primitive zilizofungashwa

// Broken comparator - can you spot the flaw?
Comparator<Integer> naturalOrder = (i, j) -> (i < j) ? -1 : (i == j ? 0 : 1);

26. Rejelea vitu kupitia violesura vyake

Mfano mzuri:

Set<Son> sonSet = new LinkedHashSet<>();

Mfano mbaya:

LinkedHashSet<Son> sonSet = new LinkedHashSet<>();

27. Pendelea violesura kuliko reflection

Vinginevyo:

28. Fuata kanuni za majina zinazokubalika kwa ujumla

Jukwaa la Java lina seti thabiti ya kanuni za majina, nyingi zikiwa zimo katika The Java Language Specification [JLS, 6.1].

29. Tumia exceptions kwa hali za kipekee tu

// Horrible abuse of exceptions. Don't ever do this!
try {
    int i = 0;
    while (true) {
        range[i++].climb();
    }
} catch (ArrayIndexOutOfBoundsException e) {
    // catch it
}

Msimbo huu unafanya nini? Haieleweki hata kidogo ukiuchunguza, na hiyo ni sababu tosha ya kutoutumia. Inabainika kuwa ni mtindo uliobuniwa vibaya mno wa kupitia vipengele vya safu. Kitanzi kisicho na mwisho kinakoma kwa kurusha, kukamata na kupuuza ArrayIndexOutOfBoundsException kinapojaribu kufikia kipengele cha kwanza nje ya mipaka ya safu. Kinadhaniwa kuwa sawa na mtindo sanifu wa kupitia safu, ambao hutambulika mara moja na mtayarishaji programu yeyote wa Java:

for (Mountain m : range) {
    m.climb();
}

Exceptions, kama jina lake linavyoashiria, zinapaswa kutumika kwa hali za kipekee tu; hazipaswi kamwe kutumika kwa mtiririko wa kawaida wa udhibiti.

30. Tumia checked exceptions kwa hali zinazoweza kurekebishwa na runtime exceptions kwa makosa ya upangaji programu

Tumia checked exceptions kwa hali ambazo mwitaji anaweza kutarajiwa kwa busara kujinasua kutoka kwazo. Kwa kumkabili mtumiaji na checked exception, mbunifu wa API anatoa agizo la kujinasua kutoka hali hiyo. Mtumiaji anaweza kupuuza agizo hilo kwa kukamata exception na kuipuuza, lakini kwa kawaida hilo ni wazo baya.

Tumia runtime exceptions kuonyesha makosa ya upangaji programu. Sehemu kubwa ya runtime exceptions zinaonyesha ukiukaji wa masharti ya awali. Ukiukaji wa sharti la awali ni kushindwa tu kwa mteja wa API kutii mkataba uliowekwa na vipimo vya API hiyo. Kwa mfano, mkataba wa kufikia safu unabainisha kwamba faharasa ya safu lazima iwe kati ya sifuri na urefu wa safu toa moja, zote zikijumuishwa. ArrayIndexOutOfBoundsException inaonyesha kwamba sharti hili la awali limekiukwa.

31. Epuka matumizi yasiyo ya lazima ya checked exceptions

Kwa muhtasari, zikitumiwa kwa kiasi, checked exceptions zinaweza kuongeza kutegemewa kwa programu; zikitumiwa kupita kiasi, zinafanya API kuwa kero kutumia.

Pair<Boolean, LearningCardGroup> answerLearningCard(@NotNull LearningCardGroup learningCardGroup,
                                                      LearningCardAssignment learningCardAssignment,
                                                      @NotNull Collection<AnswerOption> answers)
      throws InvalidTrainingStateException, PersistenceException, LearningCardGroupAlreadyCompletedException,
             ConsecutiveCorrectCountExceededException,
             PreviousLearningCardGroupUncompletedException, LearningCardGroupCooldownException,
             LearningCardGroupHasUncompletedLearningCardsException, InvalidParticipantException, TrainingNotSignedException; // but why ???
     // this is a mistake seen a lot with junior devs
     // exceptions are exceptionally slow and should be avoided for mere validation
     // the performance gets even worse if a stacktrace is printed, since logging and printing is one of the slowest possible actions

32. Pendelea kutumia exceptions sanifu

Sifa inayotofautisha watayarishaji programu mahiri na wale wenye uzoefu mdogo ni kwamba mahiri hujitahidi kufikia, na kwa kawaida hufanikiwa kufikia, kiwango cha juu cha kutumia msimbo tena.

Exceptions haziko nje ya kanuni kwamba kutumia msimbo tena ni jambo jema. Maktaba za Java zinatoa seti ya exceptions inayokidhi mahitaji mengi ya kurusha exceptions ya API nyingi. Kutumia tena exceptions sanifu kuna faida kadhaa. Kubwa zaidi ni kwamba kunafanya API yako iwe rahisi kujifunza na kutumia, kwa sababu inalingana na desturi zilizozoeleka ambazo watayarishaji programu tayari wanazifahamu. Inayofuata kwa ukaribu ni kwamba programu zinazotumia API yako ni rahisi kusoma kwa sababu hazijajaa exceptions zisizozoeleka. Mwisho (na ya chini zaidi), madarasa machache ya exceptions yanamaanisha matumizi madogo ya kumbukumbu na muda mfupi wa kupakia madarasa.

Aina ya exception inayotumiwa tena mara nyingi zaidi ni IllegalArgumentException. Kwa ujumla hii ndiyo exception ya kurusha mwitaji anapopitisha hoja yenye thamani isiyofaa. Kwa mfano, hii ndiyo exception ya kurusha ikiwa mwitaji alipitisha namba hasi katika kigezo kinachowakilisha idadi ya mara ambazo kitendo fulani kinapaswa kurudiwa. Exception nyingine inayotumiwa tena mara nyingi ni IllegalStateException. Kwa ujumla hii ndiyo exception ya kurusha ikiwa mwito si halali kwa sababu ya hali ya kitu kinachopokea. Kwa mfano, hii ndiyo exception ya kurusha ikiwa mwitaji alijaribu kutumia kitu kabla hakijaanzishwa ipasavyo.

Inaweza kusemwa kwamba kila mwito wa mbinu wenye makosa hatimaye unatokana na hoja au hali isiyo halali, lakini exceptions nyingine hutumika kwa desturi kwa aina fulani za hoja na hali zisizo halali. Ikiwa mwitaji anapitisha null katika kigezo ambacho thamani za null zimekatazwa, desturi inaagiza kwamba NullPointerException irushwe badala ya IllegalArgumentException. Vivyo hivyo, ikiwa mwitaji anapitisha thamani iliyo nje ya masafa katika kigezo kinachowakilisha faharasa ndani ya mfuatano, IndexOutOfBoundsException inapaswa kurushwa badala ya IllegalArgumentException.

Usitumie tena Exception, RuntimeException, Throwable au Error moja kwa moja. Yachukulie madarasa haya kana kwamba ni dhahania. Hata hivyo RuntimeException inaweza kutumika ikiwa unataka kugeuza checked exception kuwa runtime exception, na unajua kweli unachofanya.

33. Usipuuze exceptions

// Empty catch block ignores exception - Highly suspect!
try {
    ...
} catch (SomeException e) {
}

Kizuizi cha catch kilicho tupu kinavunja madhumuni ya exceptions, ambayo ni kukulazimisha kushughulikia hali za kipekee. Kupuuza exception ni sawa na kupuuza kengele ya moto – na kuizima ili mtu mwingine yeyote asipate nafasi ya kuona kama kuna moto halisi.