ต่อไปนี้จะแสดงต่อทุกคนสำหรับความเข้าใจผิดแต่ละครั้ง
1. การใช้งานมากเกินไปของ NULL
การหลีกเลี่ยงการใช้งาน NULL มากเกินไปเป็นแนวปฏิบัติที่ดีที่สุด ตัวอย่างเช่นวิธีที่ดีกว่าคือการทำให้วิธีการกลับไปที่อาร์เรย์หรือคอลเลกชันที่ว่างเปล่าแทนที่จะเป็นค่า NULL เพราะสิ่งนี้สามารถป้องกันไม่ให้โปรแกรมโยน nullpointerexception ส่วนโค้ดต่อไปนี้จะได้รับการรวบรวมจากวิธีอื่น:
รายการ <String> accountIds = person.getAccountIds ();
เมื่อตัวเลขไม่มีบัญชี GetAccountIds () จะส่งคืนค่า NULL และโปรแกรมจะทำให้ข้อยกเว้น NullPointerException ออกมา ดังนั้นจึงจำเป็นต้องเข้าร่วมการตรวจสอบอากาศเพื่อแก้ปัญหานี้ หากคุณแทนที่ค่า null ที่ส่งคืนด้วยรายการว่างเปล่า NullPointerException จะไม่ปรากฏขึ้น ยิ่งกว่านั้นเนื่องจากเราไม่จำเป็นต้องตรวจสอบสั้น ๆ ของตัวแปรบัญชีรหัสจะกระชับมากขึ้น
เมื่อคุณต้องการหลีกเลี่ยงค่า NULL สถานการณ์ที่แตกต่างกันอาจใช้วิธีปฏิบัติที่แตกต่างกัน วิธีหนึ่งคือการใช้ประเภทเสริมซึ่งอาจเป็นทั้งวัตถุเปล่าหรือแพ็คเกจของค่าบางอย่าง
ตัวเลือก <String> OptionAlsTring = ontaint.ofnullable (NulledString);
ในความเป็นจริง Java8 ให้วิธีที่กระชับมากขึ้น:
ตัวเลือก <String> OptionAlsTring = ontaint.ofnullable (nullialString);
Java ได้รองรับประเภทเสริมจากรุ่น Java8 แต่เป็นที่รู้จักกันอย่างกว้างขวางในโลกการเขียนโปรแกรมที่ใช้งานได้ ก่อนหน้านั้นมันถูกใช้ใน Java เวอร์ชันแรก ๆ ใน Google Guava
2. ละเว้นความผิดปกติ
เรามักจะเพิกเฉยต่อความผิดปกติ อย่างไรก็ตามแนวปฏิบัติที่ดีที่สุดคือการจัดการกับพวกเขาสำหรับผู้เริ่มต้นและโปรแกรมเมอร์ Java ที่มีประสบการณ์ การขว้างปาที่ผิดปกติมักจะมีจุดมุ่งหมายดังนั้นในกรณีส่วนใหญ่จึงจำเป็นต้องบันทึกเหตุการณ์ที่ทำให้เกิดความผิดปกติ อย่าประมาทเรื่องนี้ อย่างน้อยเพื่อให้นักพัฒนารายอื่นทราบสาเหตุและผลกระทบคุณควรอธิบายว่าทำไมความผิดปกตินี้จึงไม่ได้รับการจัดการ
selfie = person.shootaselfie (); ลอง {selfie.show ();} catch (nullpointterexception e) {// อาจ
วิธีง่ายๆในการเน้นย้ำที่ไม่สำคัญบางอย่างคือการใช้ข้อมูลนี้เป็นชื่อตัวแปรที่ผิดปกติเช่นนี้:
คัดลอกรหัสรหัสดังนี้:
ลอง {selfie.delete ();} catch (nullpointterexception ไม่สำคัญ) {}
3. ปรับเปลี่ยนความผิดปกติพร้อมกัน
ความผิดปกตินี้เกิดขึ้นในวัตถุคอลเลกชันและในเวลาเดียวกันไม่ได้ใช้วิธีการที่ให้โดยอ็อบเจ็กต์ตัววนซ้ำเพื่ออัปเดตเนื้อหาในคอลเลกชัน ตัวอย่างเช่นมีรายการหมวกที่นี่และคุณต้องการลบค่าทั้งหมดที่มีเกล็ดหู:
รายการ <ihats = arraylist ใหม่ <> (); hasearflaps ()) {hats.remove (หมวก);}}
หากรหัสนี้ทำงานให้กับการกำหนดพร้อมกัน Exception จะถูกโยนลงเนื่องจากรหัสจะแก้ไขในขณะที่ข้ามคอลเลกชันนี้ เมื่อกระบวนการหลายกระบวนการดำเนินการในรายการเดียวกันเมื่อกระบวนการใดกระบวนการหนึ่งผ่านรายการกระบวนการอื่น ๆ พยายามแก้ไขเนื้อหารายการและความผิดปกติเดียวกันอาจเกิดขึ้น
เป็นเรื่องธรรมดามากในเนื้อหาการรวบรวมการดัดแปลงที่เกิดขึ้นพร้อมกันหลายเธรดดังนั้นจึงจำเป็นต้องใช้วิธีการที่ใช้กันทั่วไปในการเขียนโปรแกรมพร้อมกันเช่นล็อคแบบซิงโครนัสชุดพิเศษสำหรับการดัดแปลงพร้อมกันและอื่น ๆ Java แก้ปัญหานี้ในกระทู้เดียวและสถานการณ์หลายเธรด
รวบรวมวัตถุและลบออกในรอบอื่น
ทางออกโดยตรงคือการใส่หมวกที่มีอวัยวะเพศหญิงลงในรายการจากนั้นลบออกด้วยรอบอื่น อย่างไรก็ตามสิ่งนี้ต้องมีชุดเพิ่มเติมเพื่อเก็บหมวกที่จะลบ
รายการ <ihatstoremove = ใหม่ LinkedList <> ();
ใช้วิธี iterator.remove
วิธีนี้ง่ายกว่าและในเวลาเดียวกันไม่จำเป็นต้องสร้างคอลเลกชันเพิ่มเติม:
Iterator <ihatitrator = hats.iterator ();
วิธีการใช้ listiterator
เมื่อมีการดำเนินการรวบรวมคอลเลกชันของอินเทอร์เฟซรายการรายการ Iterator เป็นตัวเลือกที่เหมาะสมมาก ตัววนซ้ำที่ใช้อินเทอร์เฟซของ Listitoror ไม่เพียง แต่รองรับการดำเนินการลบ แต่ยังรองรับการเพิ่มและตั้งค่าการดำเนินงาน อินเทอร์เฟซ liStOtrator ใช้อินเทอร์เฟซตัววนซ้ำดังนั้นตัวอย่างนี้จึงมีลักษณะคล้ายกับวิธีการลบของตัววนซ้ำ ความแตกต่างเพียงอย่างเดียวคือประเภทของตัววนซ้ำ HAT และเราได้รับเมธอดตัววนซ้ำ -ใช้วิธี liStOTRATOR () ชิ้นส่วนต่อไปนี้แสดงวิธีการใช้ listterator.remove และ listotrator.add วิธีการแทนที่หมวก flaps หูด้วย som <ombreros
ihat sombrero = new sombrero (); ;
การใช้ listiterator การเรียกใช้การลบและเพิ่มวิธีการสามารถแทนที่เพื่อเรียกใช้วิธีเดียวเพียงชุดเดียว:
ihat sombrero = new sombrero (); ); // ตั้งค่าแทนการลบและเพิ่ม}}}
ใช้วิธีการสตรีมใน Java 8
ใน Java8 นักพัฒนาสามารถแปลงคอลเลกชันเป็นสตรีมและสตรีมตัวกรองตามเงื่อนไขบางประการ ตัวอย่างนี้บอกได้ว่าหมวกตัวกรอง API ของสตรีมและหลีกเลี่ยงการทำงานร่วมกันพร้อมกัน หมวก = hats.stream ()
คัดลอกรหัสรหัสดังนี้:
.Collect (collector.tocollection (arraylist :: ใหม่));
วิธีการสะสมของ Tocollection จะสร้าง ArrayList ใหม่ซึ่งรับผิดชอบในการจัดเก็บค่า HATS ที่ผ่านการกรอง หากเงื่อนไขการกรองถูกกรองออกเป็นจำนวนมากรายการอาร์เรย์ขนาดใหญ่จะถูกสร้างขึ้นที่นี่ ดังนั้นคุณต้องใช้มันด้วยความระมัดระวัง
ใช้วิธี list.removeif ใน Java 8
คุณสามารถใช้วิธีการที่กระชับและชัดเจนยิ่งขึ้นในวิธี Java 8 -removeif: วิธีการ:
คัดลอกรหัสรหัสดังนี้:
hats.removeif (ihat :: hasearflaps);
ที่ด้านล่างจะใช้ iterator.remove เพื่อดำเนินการนี้ให้เสร็จสิ้น
ใช้คอลเล็กชันพิเศษ
หากคุณตัดสินใจที่จะใช้ CopyOnWriteArrayList แทน arrayList ในตอนแรกจะไม่มีปัญหา เนื่องจาก CopyOnWriteArrayList มีวิธีการแก้ไข (เช่น Set, Add, Remove) จึงไม่เปลี่ยนอาร์เรย์คอลเลกชันดั้งเดิม แต่สร้างเวอร์ชันที่แก้ไขใหม่ สิ่งนี้ช่วยให้ Traversal สามารถปรับเปลี่ยนเวอร์ชันดั้งเดิมเพื่อให้การรับรู้ร่วมกันพร้อมกันไม่ได้ถูกโยนออกไป ข้อเสียของคอลเลกชันนี้ยังชัดเจนมาก -คอลเลกชันใหม่ถูกสร้างขึ้นสำหรับการดัดแปลงแต่ละครั้ง
มีชุดอื่น ๆ ที่เหมาะสมสำหรับสถานการณ์ที่แตกต่างกันเช่น CopyOnWriteset และพร้อมกัน
เกี่ยวกับข้อผิดพลาดอื่นที่อาจเกิดขึ้นระหว่างการดัดแปลงพร้อมกันมันจะสร้างสตรีมจากคอลเลกชัน เกณฑ์ทั่วไปสำหรับสตรีมคือการหลีกเลี่ยงการแก้ไขคอลเลกชันด้านหลังเมื่อตรวจสอบสตรีม ตัวอย่างถัดไปจะแสดงวิธีจัดการสตรีมอย่างถูกต้อง:
รายการ <ihat> filedhats = hats.stream ()
วิธีการ PEEK รวบรวมองค์ประกอบทั้งหมดและดำเนินการที่กำหนดไว้สำหรับแต่ละองค์ประกอบ ที่นี่การดำเนินการคือพยายามลบข้อมูลจากรายการพื้นฐานซึ่งเห็นได้ชัดว่าผิด เพื่อหลีกเลี่ยงการดำเนินการดังกล่าวคุณสามารถลองใช้วิธีการบางอย่างที่อธิบายไว้ข้างต้น
4. การป้องกัน
บางครั้งเพื่อที่จะทำงานร่วมกันได้ดีขึ้นรหัสที่จัดทำโดยห้องสมุดมาตรฐานหรือบุคคลที่สามจะต้องปฏิบัติตามการพึ่งพาทั่วไป ตัวอย่างเช่นมีความจำเป็นที่จะต้องปฏิบัติตามข้อตกลงร่วมกันระหว่าง HashCode และ Equals เพื่อให้แน่ใจว่าชุดคลาสการรวบรวมในกรอบการรวบรวม Java และคลาสอื่น ๆ โดยใช้วิธี HashCode และ Equals สามารถทำงานได้ตามปกติ อย่าปฏิบัติตามข้อผิดพลาดเช่นข้อยกเว้นหรือทำลายการรวบรวมรหัส;
รหัสข้อผิดพลาดอาจแอบเข้าไปในสภาพแวดล้อมการผลิตทำให้เกิดผลข้างเคียงมากมาย ซึ่งรวมถึงประสบการณ์ UI ที่ไม่ดีรายงานข้อมูลที่ไม่ถูกต้องประสิทธิภาพแอปพลิเคชันที่ไม่ดีการสูญเสียข้อมูลหรือมากกว่า โชคดีที่ข้อผิดพลาดภัยพิบัติเหล่านี้ไม่ได้เกิดขึ้นบ่อยครั้ง HashCode และ Equals ได้รับการกล่าวถึงก่อนหน้านี้ว่าฉากที่ปรากฏอาจเป็น: คอลเลกชันขึ้นอยู่กับเป้าหมายเพื่อเปรียบเทียบวัตถุหรือเปรียบเทียบเช่น HashMap และ Hashset กล่าวง่ายๆว่ามีสองเกณฑ์สำหรับข้อตกลงนี้:
หากวัตถุทั้งสองเท่ากันรหัสแฮชจะต้องเท่ากัน
หากวัตถุทั้งสองมีรหัสแฮชเดียวกันพวกเขาอาจจะเท่ากันหรือแตกต่างกัน
เกณฑ์แรกสำหรับการทำลายล้างเมื่อคุณพยายามดึงข้อมูลจาก HashMap มันจะทำให้เกิดข้อผิดพลาด เกณฑ์ที่สองหมายความว่าวัตถุที่มีรหัสแฮชเดียวกันไม่จำเป็นต้องเท่ากัน
ลองมาดูผลที่ตามมาจากการทำลายเกณฑ์แรก:
เรือสแตติกสาธารณะ {ชื่อสตริงส่วนตัว; getClass ()! int hashCode () {return (int) (math.random () * 5000);}}
อย่างที่คุณเห็นคลาสเรือจะเขียนวิธีการเท่ากับและ hashcode อย่างไรก็ตามมันทำลายข้อตกลงเนื่องจาก HashCode ส่งคืนค่าสุ่มสำหรับวัตถุเดียวกันสำหรับการโทรแต่ละครั้ง รหัสต่อไปนี้มีแนวโน้มที่จะไม่พบเรือที่เรียกว่า Enterprise ใน HashSet แม้ว่าในความเป็นจริงเราได้เพิ่มเรือประเภทนี้ล่วงหน้า:
โมฆะคงที่สาธารณะหลัก (String [] args) {Set <boat> เรือ = ใหม่ hashset <> (); (เรือใหม่ ("Enterprise"));};}
ข้อตกลงอื่นคือวิธีการสรุป นี่คือการอ้างอิงถึงเอกสาร Java อย่างเป็นทางการเกี่ยวกับคำอธิบายการทำงาน:
ข้อตกลงทั่วไปของ Finalize คือ: เมื่อเครื่องเสมือน Javatm กำหนดว่าเธรดใด ๆ ไม่สามารถเข้าถึงวัตถุที่ระบุได้อีกต่อไปวิธีนี้จะถูกเรียก วิธีการสุดท้ายมีหลายฟังก์ชั่นรวมถึงการใช้วัตถุนี้ที่จะใช้ได้กับเธรดอื่น ๆ อีกครั้ง ตัวอย่างเช่นวิธีสุดท้ายที่ระบุวัตถุการเชื่อมต่ออินพุต/เอาต์พุตสามารถเรียกใช้ธุรกรรม I/O ที่ชัดเจนเพื่อขัดจังหวะการเชื่อมต่อก่อนที่วัตถุที่ถูกทิ้งถาวร
คุณสามารถตัดสินใจใช้วิธีการสรุปในตัวประมวลผลไฟล์เพื่อปล่อยทรัพยากร แต่การใช้งานนี้ไม่ดี เนื่องจากมันถูกเรียกในระหว่างการรีไซเคิลขยะและเวลาของ GC ไม่แน่ใจเวลาสำหรับการสรุปจะไม่สามารถรับประกันได้
5. ใช้ประเภทดั้งเดิมแทนการกำหนดพารามิเตอร์
ตามคำอธิบายเอกสาร Java: ประเภทต้นฉบับไม่ได้เป็นแบบไม่มีพารามิเตอร์หรือสมาชิกที่ไม่ใช่ -คงที่ของ RM (ยังไม่ใช่ in -inheritance ของ R Parent หรือ Interface Parent) ก่อนที่จะมีการแนะนำประเภท Java Generic ไม่มีประเภททางเลือกดั้งเดิม Java สนับสนุนการเขียนโปรแกรมทั่วไปจากเวอร์ชัน 1.5 และไม่ต้องสงสัยเลยว่านี่เป็นการปรับปรุงฟังก์ชั่นที่สำคัญ อย่างไรก็ตามเนื่องจากความเข้ากันได้ย้อนหลังมีกับดักที่นี่ที่อาจทำลายระบบประเภททั้งหมด พยายามตัวอย่าง:
listofnumbers = new ArrayList ();
นี่คือรายการตัวเลขที่กำหนดเป็น ArrayList ดั้งเดิม เนื่องจากไม่ได้ระบุพารามิเตอร์ประเภทจึงสามารถเพิ่มวัตถุใด ๆ ลงไปได้ อย่างไรก็ตามบรรทัดสุดท้ายแมปองค์ประกอบที่มีอยู่ในประเภท int และคูณด้วย 2 พิมพ์ข้อมูลหลังจากสองเท่าของข้อมูลไปยังเอาต์พุตมาตรฐาน
รหัสนี้จะไม่ทำให้เกิดข้อผิดพลาดในระหว่างการรวบรวม แต่เมื่อทำงานแล้วมันจะทำให้เกิดข้อผิดพลาดเมื่อมันทำงานเพราะมันพยายามแมปชนิดอักขระกับการทำศัลยกรรมพลาสติก เห็นได้ชัดว่าหากข้อมูลที่จำเป็นถูกซ่อนระบบประเภทจะไม่ช่วยเขียนรหัสความปลอดภัย
ในการแก้ปัญหานี้คุณต้องระบุประเภทเฉพาะสำหรับวัตถุในคอลเลกชัน:
รายการ <อินเทอร์> listofnumbers = new ArrayList <() ();
ความแตกต่างเพียงอย่างเดียวจากรหัสก่อนหน้าคือบรรทัดที่กำหนดคอลเลกชัน:
คัดลอกรหัสรหัสดังนี้:
รายการ <จำนวนเต็ม> listofnumbers = new ArrayList <();
การรวบรวมรหัสที่แก้ไขไม่สามารถส่งผ่านได้เนื่องจากกำลังพยายามเพิ่มสตริงลงในคอลเลกชันของพลาสติกที่จัดเก็บข้อมูลที่คาดหวังเท่านั้น คอมไพเลอร์จะแสดงข้อความแสดงข้อผิดพลาดและชี้ไปที่บรรทัดที่เพิ่มอักขระยี่สิบตัวลงในรายการ การกำหนดพารามิเตอร์ประเภททั่วไปเป็นความคิดที่ดี ในกรณีนี้คอมไพเลอร์สามารถตรวจสอบประเภทที่เป็นไปได้เพื่อให้โอกาสที่ผิดปกติของรันไทม์เนื่องจากความไม่สอดคล้องกันจะลดลงอย่างมาก
บทสรุปหลักของโปรแกรมเมอร์ Java Five ข้างต้นมักจะทำผิดพลาดฉันหวังว่าทุกคนจะชอบ