ฉันคิดว่าคุณคงเคยประสบกับสถานการณ์ที่คุณรันโค้ดและจบลงด้วยบางสิ่งเช่น a NullPointerException , ClassCastExceptionหรือแย่กว่านั้น... ตามมาด้วยกระบวนการดีบัก วิเคราะห์ googling และอื่นๆ ที่ใช้เวลานาน ข้อยกเว้นนั้นยอดเยี่ยมตามที่เป็น: สิ่งเหล่านี้บ่งชี้ถึงลักษณะของปัญหาและตำแหน่งที่เกิดขึ้น หากคุณต้องการฟื้นฟูความจำและเรียนรู้เพิ่มเติมเล็กน้อย โปรดดูบทความนี้: ข้อยกเว้น: ทำเครื่องหมาย ยกเลิกการเลือก และกำหนดเอง

ที่กล่าวว่า อาจมีบางสถานการณ์ที่คุณจำเป็นต้องสร้างข้อยกเว้นของคุณเอง ตัวอย่างเช่น สมมติว่ารหัสของคุณต้องการขอข้อมูลจากบริการระยะไกลที่ไม่สามารถใช้งานได้ด้วยเหตุผลบางประการ หรือสมมติว่ามีคนกรอกใบสมัครบัตรธนาคารและให้หมายเลขโทรศัพท์ที่เชื่อมโยงกับผู้ใช้รายอื่นในระบบไม่ว่าจะโดยบังเอิญหรือไม่ก็ตาม

แน่นอน ลักษณะการทำงานที่ถูกต้องที่นี่ยังคงขึ้นอยู่กับความต้องการของลูกค้าและสถาปัตยกรรมของระบบ แต่สมมติว่าคุณได้รับมอบหมายให้ตรวจสอบว่ามีการใช้งานหมายเลขโทรศัพท์แล้วหรือไม่ และทำข้อยกเว้นหากเป็นเช่นนั้น

มาสร้างข้อยกเว้นกัน:


public class PhoneNumberAlreadyExistsException extends Exception {

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

ต่อไปเราจะใช้เมื่อทำการตรวจสอบ:


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!");
       }
   }
}
    

เพื่อให้ตัวอย่างของเราง่ายขึ้น เราจะใช้หมายเลขโทรศัพท์แบบฮาร์ดโค้ดหลายหมายเลขเพื่อแสดงฐานข้อมูล และสุดท้าย ลองใช้ข้อยกเว้นของเรา:


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();
       }
   }
}
    

และตอนนี้ได้เวลากดShift+F10 (หากคุณใช้ IDEA) นั่นคือเรียกใช้โปรเจ็กต์ นี่คือสิ่งที่คุณจะเห็นในคอนโซล:

ข้อยกเว้น บัตรเครดิต
ออก ข้อยกเว้น หมายเลขโทรศัพท์มีอยู่แล้ว ข้อยกเว้น: ลูกค้ารายอื่นใช้หมายเลขโทรศัพท์ที่ระบุอยู่แล้ว!
ที่ exception.PhoneNumberRegisterService.validatePhone(PhoneNumberRegisterService.java:11)

ดูที่คุณ! คุณสร้างข้อยกเว้นของคุณเองและแม้แต่ทดสอบเล็กน้อย ขอแสดงความยินดีกับความสำเร็จนี้! ฉันแนะนำให้ทดลองใช้โค้ดสักเล็กน้อยเพื่อทำความเข้าใจวิธีการทำงานให้ดียิ่งขึ้น

เพิ่มการตรวจสอบอื่น เช่น ตรวจสอบว่าหมายเลขโทรศัพท์มีตัวอักษรหรือไม่ อย่างที่คุณทราบ มักใช้ตัวอักษรในสหรัฐอเมริกาเพื่อทำให้หมายเลขโทรศัพท์จำได้ง่ายขึ้น เช่น 1-800-MY-APPLE เช็คของคุณสามารถมั่นใจได้ว่าหมายเลขโทรศัพท์มีเฉพาะตัวเลขเท่านั้น

โอเค เราได้สร้างข้อยกเว้นที่ตรวจสอบแล้ว ทุกอย่างจะดีและดี แต่...

ชุมชนการเขียนโปรแกรมแบ่งออกเป็นสองค่าย - ผู้ที่สนับสนุนข้อยกเว้นที่ได้รับการตรวจสอบและผู้ที่ต่อต้านพวกเขา ทั้งสองฝ่ายโต้แย้งอย่างรุนแรง ทั้งสองรวมถึงนักพัฒนาระดับแนวหน้า: Bruce Eckel วิจารณ์ข้อยกเว้นที่ได้รับการตรวจสอบ ในขณะที่ James Gosling ปกป้องพวกเขา ดูเหมือนว่าเรื่องนี้จะไม่มีทางยุติได้อย่างถาวร ที่กล่าวว่า มาดูข้อเสียหลักของการใช้ข้อยกเว้นที่ตรวจสอบ

ข้อเสียเปรียบหลักของข้อยกเว้นที่ตรวจสอบคือต้องจัดการ และที่นี่เรามีสองตัวเลือก: จัดการกับมันโดยใช้try-catchหรือถ้าเราใช้ข้อยกเว้นเดียวกันในหลาย ๆ ที่ ให้ใช้การโยนเพื่อโยนข้อยกเว้นขึ้น และประมวลผลในคลาสระดับบนสุด

นอกจากนี้ เราอาจลงเอยด้วยโค้ด "สำเร็จรูป" นั่นคือโค้ดที่ใช้พื้นที่มากแต่ไม่ได้ยกของหนักมากนัก

ปัญหาเกิดขึ้นในแอปพลิเคชันที่ค่อนข้างใหญ่โดยมีการจัดการข้อยกเว้นจำนวนมาก: รายการ การโยนในวิธีการระดับบนสุดสามารถเติบโตได้อย่างง่ายดายเพื่อรวมข้อยกเว้นโหล

สาธารณะ OurCoolClass() โยน FirstException, SecondException, ThirdException, ApplicationNameException...

นักพัฒนามักจะไม่ชอบสิ่งนี้และเลือกใช้กลอุบายแทน: พวกเขาทำให้ข้อยกเว้น ที่ตรวจสอบแล้วทั้งหมดสืบทอดมาจากบรรพบุรุษร่วมกัน — ApplicationNameException ตอนนี้พวกเขาต้องจับข้อยกเว้นนั้นด้วย ( checked !) ในตัวจัดการ:


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

ที่นี่เราประสบปัญหาอื่น - เราควรทำอย่างไรในcatch block สุดท้าย ข้างต้น เราได้ประมวลผลสถานการณ์ที่คาดไว้ทั้งหมดแล้ว ดังนั้น ณ จุดนี้ApplicationNameExceptionไม่มีความหมายอะไรสำหรับเรามากไปกว่า " ข้อยกเว้น : มีข้อผิดพลาดบางอย่างที่ไม่สามารถเข้าใจได้เกิดขึ้น" นี่คือวิธีที่เราจัดการ:


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

และสุดท้าย เราไม่รู้ว่าเกิดอะไรขึ้น

แต่เราไม่สามารถทิ้งทุกข้อยกเว้นพร้อมกันได้ แบบนี้เหรอ?


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

ใช่เราทำได้ แต่ "โยนข้อยกเว้น" บอกอะไรเรา ว่ามีบางอย่างแตกหัก คุณจะต้องตรวจสอบทุกอย่างจากบนลงล่างและทำความคุ้นเคยกับดีบักเกอร์เป็นเวลานานเพื่อทำความเข้าใจเหตุผล

คุณอาจพบโครงสร้างที่บางครั้งเรียกว่า "การกลืนข้อยกเว้น":


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

ไม่มีคำอธิบายเพิ่มเติมที่นี่ — รหัสทำให้ทุกอย่างชัดเจน หรือค่อนข้างทำให้ทุกอย่างชัดเจน

แน่นอน คุณอาจบอกว่าคุณจะไม่เห็นสิ่งนี้ในโค้ดจริง เรามาดูส่วนลึก (โค้ด) ของ คลาส URLจากแพ็คเกจjava.net กัน อยากรู้ตามมาเลย!

นี่คือหนึ่งในโครงสร้างใน คลาส URL :


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

อย่างที่คุณเห็น เรามีข้อยกเว้นการตรวจสอบที่น่าสนใจ— MalformedURLException ต่อไปนี้อาจเกิดขึ้น (และฉันอ้าง):
"หากไม่ได้ระบุโปรโตคอล หรือพบโปรโตคอลที่ไม่รู้จัก หรือข้อมูลจำเพาะเป็นโมฆะ หรือ URL ที่แยกวิเคราะห์ไม่เป็นไปตามไวยากรณ์เฉพาะของโปรโตคอลที่เกี่ยวข้อง"

นั่นคือ:

  1. หากไม่มีการระบุโปรโตคอล
  2. พบโปรโตคอลที่ไม่รู้จัก
  3. ข้อมูลจำเพาะเป็นโมฆะ
  4. URL ไม่เป็นไปตามไวยากรณ์เฉพาะของโปรโตคอลที่เกี่ยวข้อง

มาสร้างวิธีการสร้าง วัตถุ URL :


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

ทันทีที่คุณเขียนบรรทัดเหล่านี้ใน IDE (ฉันกำลังเข้ารหัสใน IDEA แต่ใช้งานได้แม้ใน Eclipse และ NetBeans) คุณจะเห็นสิ่งนี้:

ซึ่งหมายความว่าเราจำเป็นต้องส่งข้อยกเว้นหรือรวมรหัสไว้ในบล็อกtry-catch สำหรับตอนนี้ ฉันขอแนะนำให้เลือกตัวเลือกที่สองเพื่อให้เห็นภาพสิ่งที่เกิดขึ้น:


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

อย่างที่คุณเห็น โค้ดนั้นค่อนข้างละเอียดอยู่แล้ว และเราได้กล่าวถึงข้างต้น นี่เป็นหนึ่งในเหตุผลที่ชัดเจนที่สุดในการใช้ข้อยกเว้นที่ไม่ได้ตรวจสอบ

เราสามารถสร้างข้อยกเว้นที่ไม่ได้ตรวจสอบได้โดยขยายRuntimeExceptionใน Java

ข้อยกเว้นที่ไม่ได้ตรวจสอบจะสืบทอดมาจาก คลาส ErrorหรือคลาสRuntimeException โปรแกรมเมอร์หลายคนรู้สึกว่าสามารถจัดการกับข้อยกเว้นเหล่านี้ในโปรแกรมของเราได้ เนื่องจากข้อผิดพลาดเหล่านี้แสดงถึงข้อผิดพลาดที่เราไม่สามารถคาดหวังให้กู้คืนได้ในขณะที่โปรแกรมกำลังทำงาน

เมื่อเกิดข้อยกเว้นที่ไม่ได้ตรวจสอบ มักเกิดจากการใช้โค้ดไม่ถูกต้อง ส่งผ่านอาร์กิวเมนต์ที่เป็นโมฆะหรือไม่ถูกต้อง

มาเขียนโค้ดกัน:


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);
   }
}
    

โปรดทราบว่าเราได้สร้างตัวสร้างหลายตัวเพื่อวัตถุประสงค์ที่แตกต่างกัน สิ่งนี้ช่วยให้เราเพิ่มความสามารถให้กับข้อยกเว้นของเรา ตัวอย่างเช่น เราสามารถสร้างข้อยกเว้นให้รหัสข้อผิดพลาดแก่เราได้ ในการเริ่มต้น เรามาสร้างenumเพื่อแสดงรหัสข้อผิดพลาดของเรา:


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;
   }
}
    

ตอนนี้ให้เพิ่มตัวสร้างอื่นในคลาสข้อยกเว้นของเรา:


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

และอย่าลืมเพิ่มฟิลด์ (เราเกือบลืม):


private Integer errorCode;
    

และแน่นอน วิธีการรับรหัสนี้:


public Integer getErrorCode() {
   return errorCode;
}
    

ลองดูทั้งชั้นเรียนเพื่อที่เราจะตรวจสอบและเปรียบเทียบได้:

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;
   }
}
    

ทะ-ดา! ข้อยกเว้นของเราเสร็จสิ้นแล้ว! อย่างที่คุณเห็นไม่มีอะไรซับซ้อนเป็นพิเศษ ลองตรวจสอบการทำงาน:


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

เมื่อเราเรียกใช้แอปพลิเคชันขนาดเล็ก เราจะเห็นสิ่งต่อไปนี้ในคอนโซล:

ตอนนี้มาใช้ประโยชน์จากฟังก์ชันพิเศษที่เราเพิ่มเข้าไปกันเถอะ เราจะเพิ่มรหัสก่อนหน้าเล็กน้อย:


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);
}

}
    

คุณสามารถทำงานกับข้อยกเว้นในลักษณะเดียวกับที่คุณทำงานกับวัตถุ แน่นอน ฉันแน่ใจว่าคุณรู้อยู่แล้วว่าทุกอย่างใน Java เป็นวัตถุ

และดูสิ่งที่เราทำ ขั้นแรก เราเปลี่ยนวิธีการซึ่งตอนนี้ไม่โยน แต่สร้างข้อยกเว้นแทน โดยขึ้นอยู่กับพารามิเตอร์อินพุต ต่อไป เราใช้ คำสั่ง switch-caseเราสร้างข้อยกเว้นด้วยรหัสข้อผิดพลาดและข้อความที่ต้องการ และในเมธอดหลัก เราได้รับข้อยกเว้นที่สร้างขึ้น รับรหัสข้อผิดพลาด แล้วโยนทิ้ง

ลองเรียกใช้สิ่งนี้และดูว่าเราได้อะไรจากคอนโซล:

ดูสิ — เราพิมพ์รหัสข้อผิดพลาดที่เราได้รับจากข้อยกเว้น แล้วส่งข้อยกเว้นนั้นออกไป ยิ่งไปกว่านั้น เรายังสามารถติดตามได้อย่างแม่นยำว่าเกิดข้อยกเว้นขึ้นที่ใด คุณสามารถเพิ่มข้อมูลที่เกี่ยวข้องทั้งหมดลงในข้อความ สร้างรหัสข้อผิดพลาดเพิ่มเติม และเพิ่มคุณสมบัติใหม่ให้กับข้อยกเว้นได้ตามต้องการ

คุณคิดอย่างไรกับสิ่งนั้น? ฉันหวังว่าทุกอย่างจะได้ผลสำหรับคุณ!

โดยทั่วไป ข้อยกเว้นเป็นหัวข้อที่ค่อนข้างกว้างและไม่ชัดเจน จะมีการโต้เถียงกันอีกมากมาย ตัวอย่างเช่น มีเพียง Java เท่านั้นที่ตรวจสอบข้อยกเว้น ในบรรดาภาษาที่ได้รับความนิยมสูงสุด ฉันไม่เห็นภาษาใดใช้เลย

Bruce Eckel เขียนเกี่ยวกับข้อยกเว้นในบทที่ 12 ของหนังสือ "Thinking in Java" ได้ดีมาก — ฉันแนะนำให้คุณอ่าน! ลองดูเล่มแรกของ "Core Java" ของ Horstmann ด้วย — ในบทที่ 7 ยังมีสิ่งที่น่าสนใจอีกมากมาย

บทสรุปเล็กน้อย

  1. เขียนทุกอย่างลงบันทึก! บันทึกข้อความในข้อยกเว้นที่ถูกโยนทิ้ง ซึ่งโดยปกติจะช่วยได้มากในการดีบักและจะช่วยให้คุณเข้าใจว่าเกิดอะไรขึ้น อย่าปล่อยให้catch block ว่าง มิฉะนั้นจะเป็นการ "กลืน" ข้อยกเว้น และคุณจะไม่มีข้อมูลใด ๆ ที่จะช่วยคุณค้นหาปัญหา

  2. เมื่อพูดถึงข้อยกเว้น การปฏิบัติที่ไม่ดีที่จะจับพวกมันทั้งหมดในคราวเดียว (ตามที่เพื่อนร่วมงานของฉันกล่าวว่า "ไม่ใช่โปเกมอน แต่เป็น Java") ดังนั้นหลีกเลี่ยงการจับ (ข้อยกเว้น e) หรือแย่กว่านั้นคือ จับ ( โยนได้t )

  3. โยนข้อยกเว้นให้เร็วที่สุด นี่เป็นแนวทางปฏิบัติในการเขียนโปรแกรม Java ที่ดี เมื่อคุณศึกษาเฟรมเวิร์กเช่น Spring คุณจะเห็นว่าเป็นไปตามหลักการ "ล้มเหลวเร็ว" นั่นคือพวกเขา "ล้มเหลว" ให้เร็วที่สุดเพื่อให้สามารถค้นหาข้อผิดพลาดได้อย่างรวดเร็ว แน่นอนว่าสิ่งนี้นำมาซึ่งความไม่สะดวก แต่แนวทางนี้ช่วยสร้างโค้ดที่มีประสิทธิภาพมากขึ้น

  4. เมื่อเรียกใช้ส่วนอื่นๆ ของโค้ด วิธีที่ดีที่สุดคือการตรวจจับข้อยกเว้นบางอย่าง หากโค้ดที่เรียกใช้มีข้อยกเว้นหลายข้อ การเขียนโปรแกรมที่แย่คือการจับเฉพาะคลาสพาเรนต์ของข้อยกเว้นเหล่านั้น ตัวอย่างเช่น สมมติว่าคุณเรียกโค้ดที่โยนFileNotFoundExceptionและIOException ในโค้ดของคุณที่เรียกโมดูลนี้ คุณควรเขียนบล็อก catch สองบล็อกเพื่อจับข้อยกเว้นแต่ละข้อ แทนที่จะเขียนcatch ข้อยกเว้น เพียงอันเดียว

  5. จับข้อยกเว้นก็ต่อเมื่อคุณสามารถจัดการได้อย่างมีประสิทธิภาพสำหรับผู้ใช้และสำหรับการดีบัก

  6. อย่าลังเลที่จะเขียนข้อยกเว้นของคุณเอง แน่นอน Java มีแบบสำเร็จรูปมากมายสำหรับทุกโอกาส แต่บางครั้งคุณยังต้องประดิษฐ์ "วงล้อ" ของคุณเอง แต่คุณควรเข้าใจอย่างชัดเจนว่าเหตุใดคุณจึงทำเช่นนี้ และต้องแน่ใจว่าชุดข้อยกเว้นมาตรฐานไม่มีสิ่งที่คุณต้องการอยู่แล้ว

  7. เมื่อคุณสร้างคลาสยกเว้นของคุณเอง โปรดระวังเกี่ยวกับการตั้งชื่อ! คุณอาจทราบแล้วว่าการตั้งชื่อคลาส ตัวแปร เมธอด และแพ็กเกจอย่างถูกต้องเป็นสิ่งสำคัญอย่างยิ่ง ข้อยกเว้นก็ไม่มีข้อยกเว้น! :) ลงท้ายด้วยคำว่าException เสมอ และชื่อของข้อยกเว้นควรสื่อถึงประเภทของข้อผิดพลาดที่แสดงอย่างชัดเจน ตัวอย่างเช่นFileNotFoundException

  8. บันทึกข้อยกเว้นของคุณ เราแนะนำให้เขียนแท็ก @throws Javadoc เพื่อยกเว้น สิ่งนี้จะเป็นประโยชน์อย่างยิ่งเมื่อโค้ดของคุณมีส่วนต่อประสานใดๆ และคุณจะพบว่าง่ายต่อการเข้าใจรหัสของคุณเองในภายหลัง คุณคิดอย่างไร คุณจะทราบได้อย่างไรว่าMalformedURLExceptionเป็นเรื่องเกี่ยวกับ อะไร จาก Javadoc! ใช่ ความคิดในการเขียนเอกสารไม่น่าสนใจนัก แต่เชื่อฉันสิ คุณจะขอบคุณตัวเองเมื่อคุณกลับมาใช้รหัสของคุณเองในอีกหกเดือนต่อมา

  9. ปล่อยทรัพยากรและอย่าละเลยการสร้างtry-with-resources

  10. นี่คือบทสรุปโดยรวม: ใช้ข้อยกเว้นอย่างชาญฉลาด การส่งข้อยกเว้นเป็นการดำเนินการที่ค่อนข้าง "แพง" ในแง่ของทรัพยากร ในหลายกรณี อาจง่ายกว่าที่จะหลีกเลี่ยงการโยนข้อยกเว้นและส่งคืน เช่น ตัวแปรบูลีนที่ไม่ว่าการดำเนินการจะสำเร็จหรือไม่ โดยใช้ if-else ที่ง่ายและ "ถูกกว่า"

    การผูกตรรกะของแอปพลิเคชันเข้ากับข้อยกเว้นอาจเป็นการดึงดูด ซึ่งคุณไม่ควรทำอย่างชัดเจน ดังที่เรากล่าวไว้ในตอนต้นของบทความ ข้อยกเว้นมีไว้สำหรับสถานการณ์พิเศษ ไม่ใช่เหตุการณ์ที่คาดหวัง และมีเครื่องมือมากมายสำหรับป้องกัน โดยเฉพาะอย่างยิ่ง มีตัวเลือกเพื่อป้องกันNullPointerExceptionหรือScanner.hasNextและอื่นๆ ที่คล้ายกันเพื่อป้องกันIOExceptionซึ่ง เมธอด read()อาจโยนทิ้ง