Xatolar erta "ushlab turish" uchun maxsus vositalar sifatida foydalanish yaxshi bo'larmidi?

Muammolarni erta olish uchun istisnolardan foydalanaman. Misol uchun:

public int getAverageAge(Person p1, Person p2){
    if(p1 == null || p2 == null)
        throw new IllegalArgumentException("One or more of input persons is null").
    return (p1.getAge() + p2.getAge())/2;
}

Mening dasturim bu funktsiyani hech qachon null dan kechirmasligi kerak. Men hech qachon bu haqda o'ylamayman. Lekin, barchamiz bilganimizdek, dasturda istalgan natija bo'lmaydi.

Ushbu muammoning yuzaga kelishi bilan istisno olib tashlash, dasturning boshqa joylarida ko'proq muammolarga yo'l qo'ymasdan oldin, uni aniqlash va tuzatish imkonini beradi. Istisno dasturni to'xtatib, menga "yomon narsalar sodir bo'ldi, uni tuzat" deb aytdi. Buning o'rniga ushbu dasturda atrofdagi muammolarni keltirib chiqaradigan null o'rniga harakat qiladi.

Keling, siz to'g'ri, bu holda null shunchaki bir NullPointerException ga sabab bo'ladi, shuning uchun u eng yaxshi misol bo'lishi mumkin emas.

Masalan, masalan, masalan, masalan, masalan:

public void registerPerson(Person person){
    persons.add(person);
    notifyRegisterObservers(person);//sends the person object to all kinds of objects.
}

Bunday holda, parametr sifatida dastur atrofida bir null yuboriladi va juda ko'p vaqt o'tmay, xatolarga olib kelishi mumkin.

Funktsiyani quyidagicha o'zgartirish:

public void registerPerson(Person person){
    if(person == null) throw new IllegalArgumentException("Input person is null.");
    persons.add(person);
    notifyRegisterObservers(person);//sends the person object to all kinds of objects.
}

Boshqa joylarda g'alati xatolar tug'dirmasidan oldin, men bu muammoni juda aniq belgilashga imkon beradi.

Bundan tashqari, parametr sifatida null havolasi faqat namuna. Bu bekor argumentlardan boshqa har qanday narsaga qadar ko'plab muammolar bo'lishi mumkin. Ularni erta aniqlash yaxshi bo'lardi.


Shunday qilib, mening savolim shunchaki: bu yaxshi amaliyotmi? Muammolarni oldini olish vositasi sifatida istisnolardan foydalanyapmanmi? Bu istisnolardan qonuniy foydalanishmi yoki u muammolimi?

29
Java yorlig'i qo'shildi. Bu savollar har doim tilga bog'liq.
qo'shib qo'ydi muallif miguel.de.icaza, manba
IllegalArgumentException-ni tashlaganingiz uchun " Kirish shaxs» deb aytish kerak emas.
qo'shib qo'ydi muallif miguel.de.icaza, manba
Bu savol bilan nima noto'g'ri ekanligini tushuntirishga tushishi mumkinmi?
qo'shib qo'ydi muallif Giorgio, manba
@kevincline Hozir bu savol menga tegishli emas. OP o'shanda tilga xos bo'lmasa, siz unga katta zarar yetkazyapsiz va C#, VB.NET, Lisp, APL va boshqa ko'plab savollarni takrorlashga ruxsat berasiz.
qo'shib qo'ydi muallif o.m., manba
Bu Java dasturining eng yaxshi amaliyoti hisoblanadi, shuning uchun bir nechta foydali kutubxonalar osonlashtirilishi uchun mavjud. commons.apache" sahifasiga tashrif buyuring. org/proper/commons-lang/javadocs/api-2.6/org/& zwnj; & hellip; kod.google.com/p/guava-libraries/wiki/PreconditionsExplaine‌ d
qo'shib qo'ydi muallif user35925, manba
Kodlash shartnomalari sizning ko'plab xatolaringizni statik tarzda aniqlash imkonini beradi. Bu, odatda, ish vaqtida istisno chiqarishdan ustundir. Kodlash shartnomalarini qo'llab-quvvatlash va samaradorligi tilga bog'liq.
qo'shib qo'ydi muallif Brian, manba
Buning ma'nosi nima istisnolardan iborat.
qo'shib qo'ydi muallif Johanna Cristine Dy, manba
Ehtimol, , ehtimol, muvaffaqiyatsizlikka olib keladigan operatsiyalarni tavsiflash uchun? Shunday qilib, siz bunday tizimda xatoliklarni bartaraf qilish talabini kodlashingiz mumkin va hech qanday usuldan null ni qaytarib olishingiz shart emas.
qo'shib qo'ydi muallif jfs, manba
@MarkHurd Bu tilga qaram, keng gapiradi. Masalan, Java'da nima qilayotganingizni C ++ deb aytish mumkin. Biz nihoyat bloklar, axlat yig'ish mavjudligiga umid qilamiz, chunki biz halokat va tashlashni tashvishga solmaymiz. Zamonaviy istisno yondashuv til uchun universal emas.
qo'shib qo'ydi muallif Nathan Cooper, manba
@ user2236631 Ushbu kod java ("zamonaviy" istisnosiz ishlash bilan tilni ifodalaydigan) kabi ko'rinadi, bu juda yomon dasturdir.
qo'shib qo'ydi muallif Nathan Cooper, manba
Yuqoridagi misolda nullni qaytarib olish va istisnoni markazlashtirilgan tarzda bajarish yaxshiroq bo'lar edi ... agar har bir kichik usul har qanday kichik masala uchun kirish parametrlari bilan istisno qilsa, kod minglab ularni alohida-alohida boshqarishi kerak bo'ladi ... chalkashliklarga aylanmoq ...
qo'shib qo'ydi muallif Wendy Adi, manba
"tezda qulashi, ko'pincha halokat"
qo'shib qo'ydi muallif Bryan Chen, manba

7 javoblar

Ha, "erta muvaffaqiyatsizlikka" juda yaxshi printsipdir va bu uni amalga oshirishning yagona usulidir. Va ma'lum bir qiymatni qaytarish kerak bo'lgan usullarda, siz qasddan muvaffaqiyatsiz bajarish uchun mumkin dan juda ko'p narsa yo'q - bu istisnolarni tashlash yoki tasdiqlashni tetiklash. Istisnolar «istisno» shartlarni belgilashga va dasturiy xatolarni aniqlashga mutlaqo kerak emas.

29
qo'shib qo'ydi
Bundan tashqari, "muvaffaqiyatsizlikka"
qo'shib qo'ydi muallif the0ther, manba
Agar xatolik yoki vaziyatdan qutulishning iloji bo'lmasa, u erga borishning yo'li erta. Misol uchun, agar biror faylni nusxalash kerak bo'lsa va manba yoki maqsadli yo'l bo'sh bo'lsa, darhol siz istisno qilishingiz kerak.
qo'shib qo'ydi muallif Klaws, manba

Ha, istisnolarni tashlash yaxshi fikr. Ularni tez erga tashlang, tez-tez otib tashlang, ularni g'ashingizga tashlang.

Men "istisnolar va boshqalar" deb atalgan munozaralar borligini bilaman, ba'zi bir istisno (odatda, dasturiy xatolarni aks ettiruvchi deb hisoblangan) xatti-harakatlar bilan tuzilgan tuzilmalar o'rniga ish vaqti uchun "derazadan" chiqarilishi mumkin bo'lgan tasdiqlar bilan ishlov beradigan ba'zi bir turlari bilan. Biroq, bir nechta qo'shimcha tekshiruvda ishlatiladigan ishlash miqdori zamonaviy uskunalarda minimal va har qanday qo'shimcha xarajatlar to'g'ri, uzluksiz natijalarga ega bo'lish qiymatidan juda past. Hech qachon hech qachon (ko'p) cheklarni ish vaqtida olib tashlashni istagan dastur kodi bazasini uchratmadim.

Men juda ko'p miqdorda qo'shimcha tekshiruvlar va shart-sharoitlarga ega bo'lishni istamayman, deb aytishim mumkin ... lekin aslida bu erda juda ko'p sonli xatolar yuzaga keladi va agar unda qolmasa, tashqariga barcha natijalarni ta'sir qiladi. Shunday qilib, u erda ham chexlar qilish kerak. Aslida, eng yaxshi, eng samarali soni algoritmlarning ba'zilari xatolarni baholashga asoslangan.

Qo'shimcha kodni juda yaxshi biladigan yakuniy joy - juda kechikish sezgir kod, bu erda qo'shimcha shart-sharoitlar quvur panjaralariga sabab bo'lishi mumkin. Shunday qilib, operatsion tizim, DBMS va boshqa qidiruv qavatni yadrolari va past darajadagi aloqa/protokollarni boshqarish o'rtasida. Lekin, yana bir necha joylar xatolar kuzatilishi ehtimoldan xoli emas va ularning (xavfsizlik, to'g'ri va ma'lumotlarning yaxlitligi) ta'sirlari eng xavfli bo'ladi.

Men topdim, bir yaxshilanish, faqat asosiy darajadagi istisnolardan tashlamaslikdir. IllegalArgumentException yaxshi, lekin u asosan har qanday joydan kelib chiqishi mumkin. Maxsus istisnolar qo'shish uchun ko'p tillarda ko'p narsa talab qilinmaydi. Sizning shaxsiy foydalanish modulingiz uchun quyidagilarni ayting:

public class PersonArgumentException extends IllegalArgumentException {
    public MyException(String message) {
        super(message);
    }
}

Keyin bir kishi PersonArgumentException ko'rganida, u qayerdan kelgani aniq. Qo'shish kerakli istisnolar soni haqida muvozanatlashtirilgan harakat bor, chunki keraksiz narsalarni ko'paytirishni istamaysiz (Occam's Razor). Ko'pincha odatiy bir necha maxsus istisnolardan "bu modul to'g'ri ma'lumotni olmagani" ni tasdiqlash uchun yetarli. yoki "bu modul nima qilish kerakligini qilolmaydi!" aniq va moslashtirilgan, lekin juda aniq emas, chunki siz barcha istisno ierarxiyasini qayta amalga oshirishingiz kerak. Men odatdagi maxsus istisnolar to'plamiga ko'pincha qo'shilaman va bu kodni skanerdan o'tkazib, "bu N joylar aksiyalarni istisno qilmoqdalar, lekin ular yuqori darajali fikrga ega bo'ladilar, ular ma'lumotni olmaydilar ular kerak bo'lgan narsalarni almashtirishni istaymiz, bundan qat'i nazar, nima sodir bo'layotganini yanada aniqroq tushunish uchun yuqori darajadagi istisnosiz. "

8
qo'shib qo'ydi
Hech qachon hech qachon aslida (ko'pi) tekshiruvlar bajarilgan vaqtda olib tashlashni istagan dastur kodi bazasini uchratmadim. Keyin siz bajaradigan tanqidiy kodni qildingiz. Men hozirda biror narsa ustida ishlayapman, ular 37M ni tashkil qiladi va ularsiz holda 42M mavjud. Tasdiqlashlar tashqi kirishni tasdiqlamaydi, ular kodning to'g'ri ekanligiga ishonch hosil qilish uchun o'sha erda. Mijozlarim mening narsalarim buzilmaganligidan mamnun bo'lganimdan so'ng, 13 foizga ko'payishdan baxtiyorman.
qo'shib qo'ydi muallif Schroeder, manba
Shuni e'tirof etish joizki, umumiy istisnolarni asosan xuddi shunday istisno sifatida xususiy tovarlarga rebrending zaif bir misoldir va kamdan-kam kuch sarflanadi. Amalda men alohida istisnolardan yuqori semantik darajada chiqishga harakat qilaman, bu modul niyatiga yanada yaqinroq bog'liq.
qo'shib qo'ydi muallif Jonathan Eunice, manba
Men raqamli/HPC va OS/middleware sohalarida ishlashga sezgir ishni qildim. 13% ishlash bumpi kichik narsa emas. Men uni olish uchun ba'zi tekshiruvlarni o'chirib qo'yishim mumkin, xuddi shu tarzda harbiy qo'mondon nominal reaktor chiqishi uchun 105% so'rashi mumkin. Ammo men tekshiruvlar, zaxiralar va boshqa himoya vositalarini o'chirish uchun tez-tez beriladigan "bu tezroq ishlaydi" deb ko'rdim. Bu, asosan, moslashuvchanlikni va xavfsizlikni (ko'p hollarda, ma'lumotlar yaxlitligini ham o'z ichiga oladi) ortiqcha ishlash uchun o'chirib qo'yadi. Buning foydasi bo'ladimi, sud qaroridir.
qo'shib qo'ydi muallif Jonathan Eunice, manba
Maxsus istisnolar bilan codebase-dan foydalanishni taqiqlash kerak, chunki sizga yordam berishi mumkin, ammo u siz bilan tanishish kerak bo'lgan boshqalarga yordam bermaydi. Odatda, siz o'zingizni umumiy istisnoga aylantirasiz va hech qanday a'zolar yoki funksiyalarni qo'shmasangiz, bunga ehtiyoj qolmaydi. Hatto namunangizda PersonArgumentException ham IllegalArgumentException kabi aniq emas. Ularning barchasi noqonuniy dalillar chiqarilgandan so'ng, butun dunyo bo'ylab tashlangani ma'lum. Agar Person chaqiruvi uchun yaroqsiz holatda bo'lsa, (C kodlashda InvalidOperationException ga o'xshash), agar avvalgi shaxsni tashlab yuborishini kutgan bo'lardim.
qo'shib qo'ydi muallif Selali Adobor, manba
Ehtiyot bo'lmaysiz, agar siz boshqa funktsiyadagi istisnolardan foydalanishni istasangiz, bu oddiy istisnolarning tabiati emas, balki kodning kamchiliklari. Va bu erda disk raskadrovka va stek izlari kiradi. Agar istisnolaringizni "yorliq" qilishga harakat qilsangiz, unda eng ko'p ko'rilgan istisnolardan foydalangan holda foydalaning, masalan, xost konstruktoridan foydalaning (aynan nimani anglatadi). Ba'zi istisnolar hatto muammoli dalilning nomini olish uchun qo'shimcha parametrlarga ega bo'lgan konstruktorlarni ham ta'minlaydi, biroq siz ham xuddi shunday uskunani yaxshi tashkil etilgan xabar bilan ta'minlashingiz mumkin.
qo'shib qo'ydi muallif Selali Adobor, manba

Sizning namunangizdagi funktsiyangizda siz hech qanday tekshiruv o'tkazmadingiz va faqat NullReferenceException ga ruxsat berishingizni afzal qilmoqchiman.

Birinchidan, bu erda hech qanday null o'tmaslik mantiqqa to'g'ri kelmaydi, shuning uchun men bu muammoni darhol NullReferenceException tashlashga asoslanib tushunaman.

Ikkinchidan, agar har bir funktsiya qandaydir ochiq-oydin noto'g'ri kiritilgan ma'lumotlarga asoslangan holda bir-biridan farqli istisnolardan foydalansa, unda 18 ta turli xil istisnolardan foydalanishingiz mumkin. juda ko'p ishlarni bajarish va baribir baribir barcha istisnolarni bas qilish.

Sizning funktsiyangizdagi dizayndagi xatolik yuzaga kelishiga yordam berish uchun hech narsa qilolmaysiz, shuning uchun uni o'zgartirmaguningizcha muvaffaqiyatsizlikka yo'l qo'ying.

3
qo'shib qo'ydi
"Ikkala narsa, agar har bir funktsiya qandaydir ochiq-oydin noto'g'ri ma'lumotlarning qanday turiga qarab bir oz boshqacha istisnolardan foydalansa, unda 18 ta turli xil istisnolardan foydalanishingiz mumkin bo'ladi ..." barcha funktsiyalarda bir xil istisno (hatto NullPointerException) ham foydalanishlari mumkin: har bir funktsiyadan boshqa bir istisno tashlamaslik kerak, erta otish kerak.
qo'shib qo'ydi muallif Giorgio, manba
"Birinchidan, bu erda hech qanday null o'tmaslik mantiqqa to'g'ri kelmaydi, shuning uchun muammoni darhol NullReferenceException-ni tashlashga asoslanib tushunaman." Prog ning ikkinchi misoli ko'rsatilgandek emas.
qo'shib qo'ydi muallif Giorgio, manba
Men bir necha yil davomida ushbu printsipga asoslanib kodlash asosida ishlayapman: ko'rsatgichlar kerak bo'lganda oddiygina ifodalanadi va NULLga qarshi hech qachon tekshirilmagan va ochiq-oydin ko'rib chiqilgan. Ushbu kodni disk raskadrovka qilish har doim juda ko'p vaqt talab qiluvchi va qiyinchiliklarga duch kelinadi, chunki istisnolar (yoki yadro ishqibozlari) mantiqiy xatolik bo'lgan nuqtadan keyin juda tez sodir bo'ladi. Haqiqatan ham bir necha hafta mobaynida ba'zi xatolar yuzaga kelgan. Shu sababli, hech bo'lmaganda murakkab kod uchun, null-pointer istisnosining qayerdan kelib chiqishi aniq bo'lmasa, qisqa muddatda imkon qadar tezroq usulni afzal ko'raman.
qo'shib qo'ydi muallif Giorgio, manba
RuntimeExceptions nima uchun shunday. "Bunday bo'lmasligi kerak bo'lgan har qanday shart, lekin sizning kodingizni ishlashga to'sqinlik qilishi kerak. Siz ularni imzo usulida e'lon qilishingiz shart emas. Lekin siz ularni bir nuqtada qo'lga olishingiz va so'rovlar harakati bajarilmagani haqida xabar berishingiz kerak.
qo'shib qo'ydi muallif captonssj, manba
Savolda til ko'rsatilmaydi, shuning uchun masalan. RuntimeException , albatta, to'g'ri taxminiy emas.
qo'shib qo'ydi muallif user22815, manba

Ilovani disk raskadrovka paytida iloji boricha tezroq bajarilmaydi. Eski C ++ dasturida ma'lum segmentatsion xatolikni eslayman: bug'ning aniqlangan joyi, uni kiritilgan joy bilan hech qanday aloqasi yo'q (null pointer bir joydan ikkinchisiga xotirada xotirjamlik bilan ko'chib ketgunga qadar nihoyat muammo tug'dirdi) ). Bunday holatlarda sizning izlaringiz sizga yordam bera olmaydi.

Shunday qilib, mudofaa dasturlari xatolarni tezda aniqlash va tuzatish uchun juda samarali yondashuv. Boshqa tomondan, ayniqsa, null manbalar bilan qisqartirilishi mumkin.

Sizning shaxsiy holingizda, masalan: agar mos yozuvlar biri null bo'lsa, NullReferenceException bir kishining yoshini olishga harakat qilinganda keyingi bayonotga tashlanadi. Siz o'zingizni bu yerda o'zingiz tekshirishga hojat yo'q: asosiy tizim bu xatoni qo'lga olib, istisnolarni tashlab qo'yishi mumkin, shuning uchun ular mavjud .

Haqiqiy misol uchun tasdiqlash so'zlarini ishlatishingiz mumkin, bular:

  1. Are shorter to write and read:

        assert p1 : "p1 is null";
        assert p2 : "p2 is null";
    
  2. Are specifically designed for your approach. In a world where you have both assertions and exceptions, you can distinguish them as follows:

    • Assertions are for programming errors ("/* this should never happen */"),
    • Exceptions are for corner cases (exceptional but probable situations)

Shunday qilib, o'zingizning arizangizning kiritilishi va/yoki holatiga oid taxminlaringizni oshkor qilishingiz mumkin, keyingi ishlab chiquvchi sizning kodingizning maqsadini biroz ko'proq tushunishga imkon beradi.

Statik analizator (masalan, kompilyator) ham baxtli bo'lishi mumkin.

Nihoyat, tasdiqlashlar bitta ilovadan foydalanib tarqatilgan ilovadan o'chirilishi mumkin. Umuman aytganda, samaradorlikni oshirishni kutmang: ish vaqtida tasdiqlash tekshiruvlari juda kam.

3
qo'shib qo'ydi

Umuman olganda, ha, "erta muvaffaqiyatsizlikka" tushish yaxshi. Biroq, sizning aniq misolingizda aniq kod NullReferenceException ustidan sezilarli yaxshilanishni ta'minlamaydi, chunki ikkala obyekt ham ishlayotgan bo'lsa, vazifaga argument sifatida beriladi.

Lekin bir oz boshqacha misolni ko'rib chiqaylik.

class PersonCalculator {
    PersonCalculator(Person p) {
        if (p == null) throw new ArgumentNullException("p");
        _p = p;
    }

    void Calculate() {
       //Do something to p
    }
}

Agar konstruktorda dalillar tekshirilmagan bo'lsa, Calculate deb chaqirganda NullReferenceException bo'lasiz.

Lekin kodning buzilgan qismi Calculate funktsiyasi yoki Calculate funksiyasining iste'molchisi emas edi. Kodning buzilgan qismi, PersonCalculator ni null Person bilan tuzishga harakat qiladigan kod edi, shuning uchun istisno amalga oshirilishini xohlaymiz.

Agar ushbu ochiq dalillar tekshiruvini olib tashlasak, Calculate nomi chaqirilganda nima uchun NullReferenceException nima uchun sodir bo'lganligini aniqlab olishingiz kerak. Ob'ektni nima uchun null bilan qurilganligi sababli, nima uchun bu juda murakkablasha olishi mumkin, ayniqsa, agar kalkulyatorni yaratgan kod kodi Calculate funksiyasini chaqiradigan kodga yaqin bo'lmasa.

1
qo'shib qo'ydi

Bilishimcha, turli dasturchilar bir yoki bir nechtasini afzal ko'rishadi.

Birinchi hal odatda afzal ko'riladi, chunki u qisqartiriladi, ayniqsa, turli xil funktsiyalarda bir xil holatni qayta tekshirish shart emas.

Men ikkinchi hal, masalan.

public void registerPerson(Person person){
    if(person == null) throw new IllegalArgumentException("Input person is null.");
    persons.add(person);
    notifyRegisterObservers(person);//sends the person object to all kinds of objects.
}

yanada mustahkam, chunki

  1. Bu xatni imkon qadar qisqa vaqt ichida ushlaydi, ya'ni registerPerson() chaqiruv ifodasini null pointer istisnosiz bir joyga tashlanganida emas, balki chaqirilganda emas. Xatolarni tuzatish juda osonlashadi: biz uni xato deb nomlanmasdan oldin kod orqali qanday qilib yaroqsiz qiymatga ega bo'lishi mumkinligini bilamiz.
  2. registerPerson() funktsiyalari o'rtasidagi ulanishni pasaytiradi: person argumentini va undan qanday foydalanishi haqida boshqa funktsiyalarni bajarish haqida hech qanday taxminlar qilmaydi: null deb nomlangan xatolik mahalliy ravishda olinadi va amalga oshiriladi.

Shunday qilib, ayniqsa, kod juda murakkab bo'lsa, men bu ikkinchi usulni afzal ko'rmoqchiman.

1
qo'shib qo'ydi
Buning sababi ("Input person is null."), Shuningdek, kutubxonada ba'zi noaniq usul muvaffaqiyatsizlikka duchor bo'lganda, muammoni tushunishga yordam beradi.
qo'shib qo'ydi muallif captonssj, manba

Siz bergan misollarda emas.

Aytganingizdek, siz tashlab ketishingizdan keyin siz bundan keyin istisno qilsangiz juda ko'p narsalar sizga erisha olmaydi. Ko'pchilik, yaxshi xabardagi aniq istisnoga ega bo'lishni ma'qul deb biladi, garchi men rozi bo'lmasam ham. Oldindan nashr etilgan stsenariylarda, suyak izi etarlicha yaxshi. Chiqarishdan keyingi versiyalarida, chaqiriq sayt tez-tez funktsiyalarga qaraganda yaxshi xabarlarni taqdim etishi mumkin.

Ikkinchi shakl bu funktsiyaga juda ko'p ma'lumot beradi. Bu funktsiya boshqa funktsiyalarni bo'sh kirishga olib chiqishini mutlaqo bilmasligi kerak. Nol kirishni endi ga tashlashsa ham, nol chegara kod bo'yicha tarqalib ketganligi sababli, to'xtatish kerak bo'lgan refactor uchun juda ham qiyin bo'ladi.

Ammo umuman olganda, biror narsa noto'g'ri ketganini aniqlaganingizdan so'ng, darhol tashlang. Bu, ehtimol bunga misol bo'lishi mumkin emas.

0
qo'shib qo'ydi