Aku sampeyan mbokmenawa wis ngalami kahanan sing mbukak kode lan mungkasi munggah karo kaya NullPointerException , ClassCastException , utawa Samsaya Awon ... Iki ngiring dening proses dawa debugging, nganalisa, googling, lan ing. Pangecualian apik banget: nuduhake sifat masalah lan ing ngendi kedadeyan kasebut. Yen sampeyan pengin refresh memori lan sinau mung sethitik liyane, deleng artikel iki: Pangecualian: dicenthang, ora dicenthang, lan adat .

Sing jarene, bisa uga ana kahanan nalika sampeyan kudu nggawe pangecualian dhewe. Contone, umpamane kode sampeyan kudu njaluk informasi saka layanan remot sing ora kasedhiya amarga sawetara alasan. Utawa umpamane wong ngisi aplikasi kanggo kertu bank lan menehi nomer telpon sing, ora sengaja utawa ora, wis digandhengake karo pangguna liyane ing sistem kasebut.

Mesthi, prilaku bener kene isih gumantung ing syarat customer lan arsitektur sistem, nanging ayo kang nganggep sing wis ditugasi mriksa apa nomer telpon wis digunakake lan uncalan pangecualian yen iku.

Ayo nggawe pangecualian:


public class PhoneNumberAlreadyExistsException extends Exception {

   public PhoneNumberAlreadyExistsException(String message) {
       super(message);
   }
}
    

Sabanjure kita bakal nggunakake nalika nindakake mriksa kita:


public class PhoneNumberRegisterService {
   List<String> registeredPhoneNumbers = Arrays.asList("+1-111-111-11-11", "+1-111-111-11-12", "+1-111-111-11-13", "+1-111-111-11-14");

   public void validatePhone(String phoneNumber) throws PhoneNumberAlreadyExistsException {
       if (registeredPhoneNumbers.contains(phoneNumber)) {
           throw new PhoneNumberAlreadyExistsException("The specified phone number is already in use by another customer!");
       }
   }
}
    

Kanggo nyederhanakake conto, kita bakal nggunakake sawetara nomer telpon hardcoded kanggo makili database. Lan pungkasane, ayo nyoba nggunakake pengecualian kita:


public class CreditCardIssue {
   public static void main(String[] args) {
       PhoneNumberRegisterService service = new PhoneNumberRegisterService();
       try {
           service.validatePhone("+1-111-111-11-14");
       } catch (PhoneNumberAlreadyExistsException e) {
           // Here we can write to logs or display the call stack
		e.printStackTrace();
       }
   }
}
    

Lan saiki wektune kanggo mencet Shift + F10 (yen sampeyan nggunakake IDEA), yaiku mbukak proyek kasebut. Iki sing bakal sampeyan deleng ing konsol:

exception.CreditCardIssue
exception.PhoneNumberAlreadyExistsException: Nomer telpon sing ditemtokake wis digunakake dening pelanggan liyane!
ing exception.PhoneNumberRegisterService.validatePhone(PhoneNumberRegisterService.java:11)

Delengen sampeyan! Sampeyan nggawe pangecualian dhewe lan malah nyoba rada. Sugeng prestasi iki! Aku nyaranake nyobi karo kode dicokot kanggo luwih ngerti cara kerjane.

Tambah mriksa liyane — contone, priksa manawa nomer telpon kalebu huruf. Kaya sing sampeyan ngerti, huruf asring digunakake ing Amerika Serikat kanggo nggawe nomer telpon luwih gampang dieling-eling, contone 1-800-MY-APPLE. Priksa sampeyan bisa mesthekake yen nomer telpon mung ngemot nomer.

Oke, dadi kita wis nggawe pangecualian sing dicenthang. Kabeh bakal apik lan apik, nanging ...

Komunitas pemrograman dipérang dadi rong kamp - sing milih pengecualian sing dicenthang lan sing nglawan. Loro-lorone nggawe argumentasi sing kuat. Loro-lorone kalebu pangembang paling dhuwur: Bruce Eckel ngritik pengecualian sing dicenthang, dene James Gosling mbela. Kayane prakara iki ora bakal rampung kanthi permanen. Sing jarene, ayo goleki kekurangan utama nggunakake pengecualian sing wis dicenthang.

Kerugian utama pengecualian sing dicenthang yaiku kudu ditangani. Lan ing kene kita duwe rong pilihan: salah siji nangani ing panggonan nggunakake nyoba-nyekel , utawa, yen kita nggunakake pangecualian padha ing akeh panggonan, nggunakake uncalan kanggo uncalan istiméwa munggah, lan proses ing kelas ndhuwur-tingkat.

Uga, kita bisa mungkasi karo kode "boilerplate", IE kode sing njupuk akeh papan, nanging ora nindakake akeh heavy ngangkat.

Masalah muncul ing aplikasi sing cukup gedhe kanthi akeh pangecualian sing ditangani: dhaptar uncalan ing metode tingkat paling dhuwur bisa tuwuh kanthi gampang kalebu puluhan pengecualian.

public OurCoolClass() mbuwang FirstException, SecondException, ThirdException, ApplicationNameException...

Pangembang biasane ora seneng iki lan malah milih trik: kabeh pangecualian sing dicenthang dadi warisan leluhur sing padha - ApplicationNameException . Saiki dheweke uga kudu nyekel pengecualian kasebut ( dicenthang !) ing panangan:


catch (FirstException e) {
    // TODO
}
catch (SecondException e) {
    // TODO
}
catch (ThirdException e) {
    // TODO
}
catch (ApplicationNameException e) {
    // TODO
}
    

Ing kene kita ngadhepi masalah liyane - apa sing kudu ditindakake ing blok nyekel pungkasan ? Ndhuwur, kita wis ngolah kabeh kahanan sing dikarepake, saengga ing titik iki ApplicationNameException tegese ora luwih saka " Pengecualian : sawetara kesalahan sing ora bisa dingerteni". Iki cara kita nangani:


catch (ApplicationNameException e) {
    LOGGER.error("Unknown error", e.getMessage());
}
    

Lan ing pungkasan, kita ora ngerti apa sing kedadeyan.

Nanging apa kita ora bisa mbuwang kabeh pengecualian bebarengan, kaya iki?


public void ourCoolMethod() throws Exception {
// Do some work
}
    

Ya, kita bisa. Nanging apa "mbuwang Pangecualian" marang kita? Sing ana sing rusak. Sampeyan kudu nyelidiki kabeh saka ndhuwur nganti ngisor lan kepenak karo debugger nganti suwe kanggo ngerti sebabe.

Sampeyan uga bisa nemokake konstruksi sing kadhangkala disebut "pengecualian ngulu":


try {
// Some code
} catch(Exception e) {
   throw new ApplicationNameException("Error");
}
    

Ora ana akeh sing kudu ditambahake ing kene kanthi panjelasan - kode kasebut nggawe kabeh jelas, utawa malah nggawe kabeh ora jelas.

Mesthi, sampeyan bisa ngomong yen sampeyan ora bakal weruh iki ing kode nyata. Inggih, ayo mriksa usus (kode) kelas URL saka paket java.net . Tindakake kula yen sampeyan pengin ngerti!

Iki minangka salah sawijining konstruksi ing kelas URL :


public URL(String spec) throws MalformedURLException {
   this(null, spec);
}
    

Kaya sing sampeyan ngerteni, kita duwe pengecualian sing dicenthang sing menarik - MalformedURLException . Mangkene nalika bisa dibuwang (lan aku ngutip):
"yen ora ana protokol sing ditemtokake, utawa protokol sing ora dingerteni ditemokake, utawa spek nol, utawa URL sing diurai gagal tundhuk karo sintaks tartamtu saka protokol sing gegandhengan."

Iku:

  1. Yen ora ana protokol sing ditemtokake.
  2. Protokol sing ora dingerteni ditemokake.
  3. Spesifikasinya null .
  4. URL ora tundhuk karo sintaks tartamtu saka protokol sing gegandhengan.

Ayo nggawe cara sing nggawe obyek URL :


public URL createURL() {
   URL url = new URL("https://codegym.cc");
   return url;
}
    

Sanalika sampeyan nulis baris kasebut ing IDE (Aku coding ing IDEA, nanging iki bisa digunakake sanajan ing Eclipse lan NetBeans), sampeyan bakal weruh iki:

Iki tegese kita kudu salah siji uncalan pangecualian, utawa Lebokake kode ing blok nyoba-nyekel . Saiki, aku saranake milih opsi kapindho kanggo nggambarake apa sing kedadeyan:


public static URL createURL() {
   URL url = null;
   try {
       url = new URL("https://codegym.cc");
   } catch(MalformedURLException e) {
  e.printStackTrace();
   }
   return url;
}
    

Nalika sampeyan bisa ndeleng, kode wis rada verbose. Lan kita nyebutake ing ndhuwur. Iki minangka salah sawijining alasan sing paling jelas kanggo nggunakake pengecualian sing ora dicenthang.

Kita bisa nggawe pangecualian sing ora dicenthang kanthi ngluwihi RuntimeException ing Jawa.

Pangecualian sing ora dicenthang diwarisake saka kelas Error utawa kelas RuntimeException . Akeh programer nganggep manawa pengecualian kasebut bisa ditangani ing program kita amarga nuduhake kesalahan sing ora bisa kita ngarepake nalika program lagi mlaku.

Nalika ana pangecualian sing ora dicenthang, biasane disebabake nggunakake kode sing ora bener, ngliwati argumen sing null utawa ora bener.

Inggih, ayo nulis kode:


public class OurCoolUncheckedException extends RuntimeException {
   public OurCoolUncheckedException(String message) {
       super(message);
   }

   public OurCoolUncheckedException(Throwable cause) {
       super(cause);
   }
  
   public OurCoolUncheckedException(String message, Throwable throwable) {
       super(message, throwable);
   }
}
    

Elinga yen kita nggawe macem-macem konstruktor kanggo macem-macem tujuan. Iki ngidini kita menehi pangecualian kemampuan liyane. Contone, kita bisa nggawe pangecualian menehi kode kesalahan. Kanggo miwiti, ayo nggawe enum kanggo makili kode kesalahan:


public enum ErrorCodes {
   FIRST_ERROR(1),
   SECOND_ERROR(2),
   THIRD_ERROR(3);

   private int code;

   ErrorCodes(int code) {
       this.code = code;
   }

   public int getCode() {
       return code;
   }
}
    

Saiki ayo nambah konstruktor liyane menyang kelas pengecualian:


public OurCoolUncheckedException(String message, Throwable cause, ErrorCodes errorCode) {
   super(message, cause);
   this.errorCode = errorCode.getCode();
}
    

Lan aja lali nambah kolom (kita meh lali):


private Integer errorCode;
    

Lan mesthi, cara kanggo njaluk kode iki:


public Integer getErrorCode() {
   return errorCode;
}
    

Ayo ndeleng kabeh kelas supaya bisa mriksa lan mbandhingake:

public class OurCoolUncheckedException extends RuntimeException {
   private Integer errorCode;

   public OurCoolUncheckedException(String message) {
       super(message);
   }

   public OurCoolUncheckedException(Throwable cause) {
       super(cause);
   }

   public OurCoolUncheckedException(String message, Throwable throwable) {

       super(message, throwable);
   }

   public OurCoolUncheckedException(String message, Throwable cause, ErrorCodes errorCode) {
       super(message, cause);
       this.errorCode = errorCode.getCode();
   }
   public Integer getErrorCode() {
       return errorCode;
   }
}
    

Ta-da! Pengecualian kita wis rampung! Kaya sing sampeyan ngerteni, ora ana sing rumit banget ing kene. Ayo dipriksa ing tumindak:


   public static void main(String[] args) {
       getException();
   }
   public static void getException() {
       throw new OurCoolUncheckedException("Our cool exception!");
   }
    

Nalika kita mbukak aplikasi cilik, kita bakal weruh kaya ing ngisor iki ing console:

Saiki ayo manfaatake fungsi ekstra sing wis ditambahake. Kita bakal nambah sethithik menyang kode sadurunge:


public static void main(String[] args) throws Exception {

   OurCoolUncheckedException exception = getException(3);
   System.out.println("getException().getErrorCode() = " + exception.getErrorCode());
   throw exception;

}

public static OurCoolUncheckedException getException(int errorCode) {
   return switch (errorCode) {
   case 1:
       return new OurCoolUncheckedException("Our cool exception! An error occurred: " + ErrorCodes.FIRST_ERROR.getCode(), new Throwable(), ErrorCodes.FIRST_ERROR);
   case 2:
       return new OurCoolUncheckedException("Our cool exception! An error occurred: " + ErrorCodes.SECOND_ERROR.getCode(), new Throwable(), ErrorCodes.SECOND_ERROR);
   default: // Since this is the default action, here we catch the third and any other codes that we have not yet added. You can learn more by reading Java switch statement
       return new OurCoolUncheckedException("Our cool exception! An error occurred: " + ErrorCodes.THIRD_ERROR.getCode(), new Throwable(), ErrorCodes.THIRD_ERROR);
}

}
    

Sampeyan bisa nggarap pangecualian kanthi cara sing padha karo sampeyan nggarap obyek. Mesthi, aku yakin sampeyan wis ngerti yen kabeh ing Jawa iku obyek.

Lan ndeleng apa sing ditindakake. Pisanan, kita ngganti cara, sing saiki ora mbuwang, nanging mung nggawe pangecualian, gumantung saka parameter input. Sabanjure, nggunakake statement switch-case , kita ngasilake pangecualian karo kode kesalahan lan pesen sing dikarepake. Lan ing cara utama, kita entuk pengecualian sing digawe, entuk kode kesalahan, lan mbuwang.

Ayo mbukak iki lan ndeleng apa sing kita entuk ing konsol:

Deleng - kita nyithak kode kesalahan sing kita entuk saka pangecualian lan banjur mbuwang pengecualian kasebut. Apa maneh, kita bisa nglacak persis ing ngendi pengecualian kasebut dibuwang. Yen perlu, sampeyan bisa nambah kabeh informasi sing cocog kanggo pesen, nggawe kode kesalahan tambahan, lan nambah fitur anyar kanggo pangecualian sampeyan.

Nah, apa sing sampeyan pikirake? Mugi kabeh bisa metu kanggo sampeyan!

Umumé, pangecualian minangka topik sing rada jembar lan ora cetha. Bakal akeh maneh regejegan bab iku. Contone, mung Jawa sing wis mriksa pangecualian. Ing antarane basa sing paling populer, aku durung weruh basa sing nggunakake.

Bruce Eckel nulis kanthi apik babagan pangecualian ing bab 12 saka bukune "Thinking in Java" — Aku nyaranake sampeyan maca! Deleng uga volume pisanan "Jawa Inti" Horstmann - Uga nduweni akeh perkara sing menarik ing bab 7.

Ringkesan cilik

  1. Tulis kabeh menyang log! Pesen log ing pengecualian sing dibuwang. Iki biasane bakal mbantu akeh debugging lan ngidini sampeyan ngerti apa sing kedadeyan. Aja ninggalake blok nyekel kosong, yen ora, mung bakal "nguntal" pangecualian lan sampeyan ora bakal duwe informasi kanggo mbantu sampeyan mburu masalah.

  2. Nalika nerangake pangecualian, iku laku ala nyekel kabeh bebarengan (minangka rowange saka mine ngandika, "iku ora Pokemon, iku Jawa"), supaya supaya nyekel (Istiméwa e) utawa Samsaya Awon, nyekel ( Throwable t ) .

  3. Mbuwang pangecualian minangka awal sabisa. Iki minangka praktik pemrograman Java sing apik. Nalika sampeyan sinau kerangka kaya Spring, sampeyan bakal weruh manawa dheweke ngetutake prinsip "gagal cepet". Yaiku, dheweke "gagal" sedini mungkin supaya bisa nemokake kesalahan kanthi cepet. Mesthi, iki ndadekke inconveniences tartamtu. Nanging pendekatan iki mbantu nggawe kode sing luwih kuat.

  4. Nalika nelpon bagean liyane saka kode, iku paling apik kanggo nyekel pangecualian tartamtu. Yen kode sing diarani mbuwang pirang-pirang pangecualian, praktik pamrograman sing ora apik kanggo mung nyekel kelas induk saka pengecualian kasebut. Contone, ngomong sampeyan nelpon kode sing mbalang FileNotFoundException lan IOException . Ing kode sing nelpon modul iki, iku luwih apik kanggo nulis loro pamblokiran nyekel kanggo nyekel saben pangecualian, tinimbang nyekel siji kanggo nyekel Exception .

  5. Nyekel pengecualian mung nalika sampeyan bisa nangani kanthi efektif kanggo pangguna lan kanggo debugging.

  6. Aja ragu-ragu nulis pengecualian sampeyan dhewe. Mesthi, Jawa wis akeh siap-digawe, soko kanggo saben kesempatan, nanging kadhangkala sampeyan isih kudu invent dhewe "roda". Nanging sampeyan kudu ngerti kanthi jelas kenapa sampeyan nindakake iki lan priksa manawa set pangecualian standar durung duwe apa sing sampeyan butuhake.

  7. Nalika nggawe kelas pangecualian dhewe, ati-ati babagan menehi jeneng! Sampeyan bisa uga wis ngerti manawa penting banget kanggo jeneng kelas, variabel, metode lan paket kanthi bener. Pangecualian ora istiméwa! :) Tansah dipungkasi nganggo tembung Pangecualian , lan jeneng pangecualian kudu kanthi jelas nuduhake jinis kesalahan sing diwakili. Contone, FileNotFoundException .

  8. Dokumentasi pengecualian sampeyan. Disaranake nulis tag Javadoc @throws kanggo pangecualian. Iki bakal migunani banget nalika kode sampeyan nyedhiyakake antarmuka apa wae. Lan sampeyan uga bakal luwih gampang ngerti kode sampeyan mengko. Apa sampeyan mikir, kepiye sampeyan bisa nemtokake apa sing diarani MalformedURLException ? Saka Javadoc! Ya, pikirane nulis dokumentasi ora nyenengake, nanging percayaa, sampeyan bakal matur nuwun nalika bali menyang kode dhewe nem wulan mengko.

  9. Ngeculake sumber daya lan aja nglirwakake konstruksi coba-kanggo-sumber .

  10. Mangkene ringkesan sakabèhé: gunakake pangecualian kanthi wicaksana. Mbuwang pangecualian minangka operasi sing cukup "larang" babagan sumber daya. Ing pirang-pirang kasus, bisa uga luwih gampang kanggo ngindhari pangecualian lan bali, ujare, variabel boolean manawa operasi kasebut sukses, nggunakake prasaja lan "kurang larang" yen-liyane .

    Sampeyan bisa uga nggodho kanggo ngubungake logika aplikasi menyang pangecualian, sing ora kudu ditindakake. Kaya sing wis dakkandhakake ing wiwitan artikel, pangecualian kanggo kahanan sing luar biasa, sing ora dikarepake, lan ana macem-macem alat kanggo nyegah. Ing tartamtu, ana Pilihan kanggo nyegah NullPointerException , utawa Scanner.hasNext lan kaya kanggo nyegah IOException , kang diwaca () cara bisa uncalan.