หลักการเขียนโปรแกรม
อย่าเขียนโค้ดที่ใช้งานได้จริง พยายามเขียนโค้ดที่สามารถบำรุงรักษาได้ไม่ใช่แค่คุณเท่านั้น แต่โดยใครก็ตามที่อาจลงเอยด้วยการพัฒนาซอฟต์แวร์ในอนาคต Developer ใช้เวลา 80% ในการอ่านโค้ด และ 20% ในการเขียนและทดสอบโค้ด ดังนั้นควรเน้นที่การเขียนโค้ดที่อ่านง่าย รหัสของคุณไม่ควรต้องมีความคิดเห็นเพื่อให้ใครก็ตามเข้าใจว่ามันทำอะไร ในการเขียน Code ที่ดีนั้น มีหลักการเขียนโปรแกรมมากมายที่เราสามารถใช้เป็นแนวทางได้ ด้านล่างนี้ฉันจะแสดงรายการที่สำคัญที่สุด- • KISS – ย่อมาจาก “Keep It Simple, Stupid” คุณอาจสังเกตเห็นว่านักพัฒนาในช่วงเริ่มต้นของการเดินทางพยายามใช้การออกแบบที่ซับซ้อนและคลุมเครือ
- • แห้ง - “อย่าพูดซ้ำตัวเอง” พยายามหลีกเลี่ยงการทำซ้ำใดๆ แทนที่จะรวมไว้ในส่วนเดียวของระบบหรือวิธีการ
- • YAGNI - “คุณไม่ต้องการมันหรอก” หากคุณเริ่มถามตัวเองทันทีว่า “แล้วจะเพิ่มอะไรอีก (ฟีเจอร์ โค้ด ฯลฯ) ล่ะ?” คุณอาจต้องพิจารณาว่าคุ้มที่จะเพิ่มเข้าไปจริงๆ หรือไม่
- • ทำความสะอาดโค้ดแทนโค้ดอัจฉริยะ - พูดง่ายๆ ก็คือปล่อยอัตตาของคุณไว้ที่ประตูและลืมการเขียนโค้ดอัจฉริยะไปเลย คุณต้องการโค้ดที่สะอาด ไม่ใช่โค้ดอัจฉริยะ
- • หลีกเลี่ยงการเพิ่มประสิทธิภาพก่อนเวลาอันควร - ปัญหาของการเพิ่มประสิทธิภาพก่อนเวลาอันควรคือคุณไม่มีทางรู้ได้เลยว่าปัญหาคอขวดจะอยู่ที่จุดใดในโปรแกรมจนกว่าจะปรากฏขึ้น
- • ความรับผิดชอบเดี่ยว - แต่ละคลาสหรือโมดูลในโปรแกรมควรให้ความสำคัญกับฟังก์ชันการทำงานเฉพาะเพียงเล็กน้อยเท่านั้น
- • องค์ประกอบมากกว่าการสืบทอดการใช้งาน - ออบเจ็กต์ที่มีพฤติกรรมที่ซับซ้อนควรมีอินสแตนซ์ของออบเจ็กต์ที่มีพฤติกรรมเป็นรายบุคคล แทนที่จะสืบทอดคลาสและเพิ่มพฤติกรรมใหม่
- • ยิมนาสติกแบบวัตถุ เป็นแบบฝึกหัดการเขียนโปรแกรมที่ออกแบบ มาเป็นชุดกฎ 9 ข้อ
- • ล้มเหลวเร็ว หยุดเร็ว - หลักการนี้หมายถึงการหยุดการทำงานปัจจุบันเมื่อเกิดข้อผิดพลาดที่ไม่คาดคิด การปฏิบัติตามหลักการนี้นำไปสู่การทำงานที่มีเสถียรภาพมากขึ้น
แพ็คเกจ
- จัดลำดับความสำคัญของการจัดโครงสร้างบรรจุภัณฑ์ตามสาขาวิชามากกว่าตามระดับเทคนิค
- ชอบเลย์เอาต์ที่ส่งเสริมการห่อหุ้มและการซ่อนข้อมูลเพื่อป้องกันการใช้ในทางที่ผิด แทนที่จะจัดชั้นเรียนด้วยเหตุผลทางเทคนิค
- ปฏิบัติต่อแพ็คเกจราวกับว่ามี API ที่ไม่เปลี่ยนรูป - อย่าเปิดเผยกลไกภายใน (คลาส) ที่มีไว้สำหรับการประมวลผลภายในเท่านั้น
- อย่าเปิดเผยคลาสที่มีวัตถุประสงค์เพื่อใช้ภายในแพ็คเกจเท่านั้น
ชั้นเรียน
คงที่
- ไม่อนุญาตให้สร้างคลาสแบบคงที่ สร้างคอนสตรัคเตอร์ส่วนตัวเสมอ
- คลาสแบบสแตติกควรคงสภาพไม่เปลี่ยนรูป ไม่อนุญาตให้มีคลาสย่อยหรือคลาสแบบมัลติเธรด
- คลาสแบบคงที่ควรได้รับการปกป้องจากการเปลี่ยนแปลงการวางแนว และควรจัดให้มีเป็นสาธารณูปโภค เช่น การกรองรายการ
มรดก
- เลือกองค์ประกอบมากกว่าการสืบทอด
- อย่าตั้งค่าฟิลด์ที่มีการป้องกัน ให้ระบุวิธีการเข้าถึงที่ปลอดภัย แทน
- หากตัวแปรคลาสสามารถทำเครื่องหมายเป็นFinalได้ ให้ทำเช่นนั้น
- หากไม่คาดหวังการ สืบทอดให้ทำให้คลาสเป็นขั้นสุดท้าย
- ทำเครื่องหมายวิธีการเป็นขั้นตอนสุดท้ายหากไม่คาดหวังว่าคลาสย่อยจะได้รับอนุญาตให้แทนที่วิธีการนั้น
- หากไม่จำเป็นต้องใช้ตัวสร้าง อย่าสร้างตัวสร้างเริ่มต้นโดยไม่มีตรรกะในการนำไปใช้งาน Java จะให้คอนสตรัคเตอร์เริ่มต้นโดยอัตโนมัติหากไม่มีการระบุ
อินเทอร์เฟซ
- อย่าใช้อินเทอร์เฟซของรูปแบบค่าคงที่เนื่องจากจะทำให้คลาสสามารถนำไปใช้และทำให้ API เสียหายได้ ใช้คลาสคงที่แทน สิ่งนี้มีประโยชน์เพิ่มเติมในการช่วยให้คุณสามารถเริ่มต้นออบเจ็กต์ที่ซับซ้อนมากขึ้นในบล็อกแบบคงที่ (เช่น การเติมคอลเลกชัน)
- หลีกเลี่ยงการใช้อินเทอร์เฟซมากเกินไป
- การมีคลาสเดียวที่ใช้อินเทอร์เฟซอาจนำไปสู่การใช้อินเทอร์เฟซมากเกินไปและก่อให้เกิดผลเสียมากกว่าผลดี
- "โปรแกรมสำหรับอินเทอร์เฟ ซไม่ใช่การใช้งาน" ไม่ได้หมายความว่าคุณควรรวมคลาสโดเมนแต่ละคลาสของคุณเข้ากับอินเทอร์เฟซที่เหมือนกันไม่มากก็น้อย การทำเช่นนี้คุณจะทำลายYAGNI
- รักษาอินเทอร์เฟซให้เล็กและเฉพาะเจาะจงอยู่เสมอ เพื่อให้ลูกค้าทราบเฉพาะวิธีการที่พวกเขาสนใจเท่านั้น ตรวจสอบ ISP จาก SOLID
ผู้เข้ารอบสุดท้าย
- อ็อบเจ็กต์#finalize()ควรใช้อย่างรอบคอบและเป็นเพียงวิธีการป้องกันความล้มเหลวเมื่อทำการล้างทรัพยากร (เช่น การปิดไฟล์) จัดเตรียมวิธีการล้างข้อมูลที่ชัดเจนเสมอ (เช่นclose() )
- ในลำดับชั้นการสืบทอด ให้เรียก parent's Finalize()ในtry block เสมอ การล้างข้อมูลในชั้น เรียนควรอยู่ใน บล็อก สุดท้าย
- หากไม่ได้เรียกวิธีการล้างข้อมูลอย่างชัดเจนและโปรแกรมปิดขั้นสุดท้ายปิดทรัพยากร ให้บันทึกข้อผิดพลาดนี้
- หากไม่มีตัวบันทึก ให้ใช้ตัวจัดการข้อยกเว้นของเธรด (ซึ่งท้ายที่สุดจะผ่านข้อผิดพลาดมาตรฐานที่บันทึกไว้ในบันทึก)
กฎทั่วไป
งบ
การยืนยัน ซึ่งมักจะอยู่ในรูปแบบของการตรวจสอบเงื่อนไขเบื้องต้น บังคับใช้สัญญา "ล้มเหลวอย่างรวดเร็ว หยุดอย่างรวดเร็ว" ควรใช้กันอย่างแพร่หลายเพื่อระบุข้อผิดพลาดในการเขียนโปรแกรมให้ใกล้เคียงกับสาเหตุมากที่สุด สภาพวัตถุ:- • วัตถุไม่ควรถูกสร้างขึ้นหรือทำให้อยู่ในสถานะที่ไม่ถูกต้อง
- • ใน Constructors และ Methods ให้อธิบายและบังคับใช้สัญญาโดยใช้การทดสอบเสมอ
- • ควรหลีกเลี่ยง การยืนยันคีย์เวิร์ด Java เนื่องจากสามารถปิดการใช้งานได้ และโดยปกติจะเป็นโครงสร้างที่เปราะบาง
- • ใช้ คลาสยูทิลิตี้Assertionsเพื่อหลีกเลี่ยง เงื่อนไข if-else แบบละเอียด สำหรับการตรวจสอบเงื่อนไขเบื้องต้น
ยาสามัญ
คำอธิบายโดยละเอียดโดยละเอียดเต็มรูปแบบ มีอยู่ในJava Generics FAQ ด้านล่างนี้เป็นสถานการณ์ทั่วไปที่นักพัฒนาซอฟต์แวร์ควรทราบ- เมื่อใดก็ตามที่เป็นไปได้ ควรใช้การอนุมานประเภทแทนที่จะส่งคืนคลาส/อินเทอร์เฟซพื้นฐาน:
// MySpecialObject o = MyObjectFactory.getMyObject(); public
T getMyObject(int type) { return (T) factory.create(type); } - หากไม่สามารถกำหนดประเภทได้โดยอัตโนมัติ ให้อินไลน์
public class MySpecialObject extends MyObject
{ public MySpecialObject() { super(Collections.emptyList()); // This is ugly, as we loose type super(Collections.EMPTY_LIST(); // This is just dumb // But this is beauty super(new ArrayList ()); super(Collections. emptyList()); } } - สัญลักษณ์แทน:
ใช้ ไวด์การ์ด แบบขยาย เมื่อคุณรับเฉพาะค่าจากโครงสร้าง ให้ใช้ ไวด์การ์ดพิเศษเมื่อคุณใส่เฉพาะค่าลงในโครงสร้าง และอย่าใช้ไวด์การ์ดเมื่อคุณทำทั้งสองอย่าง
- ใครๆ ก็รักPECS ! ( ผู้ผลิต-ขยาย, ผู้บริโภค-ซุปเปอร์ )
- ใช้Fooสำหรับโปรดิวเซอร์ T.
- ใช้ Foo สำหรับผู้บริโภค T.
ซิงเกิลตัน
ไม่ควรเขียนซิงเกิลตันในรูปแบบการออกแบบ คลาสสิก style ซึ่งใช้ได้ในภาษา C++ แต่ไม่เหมาะสมใน Java แม้ว่าจะปลอดภัยสำหรับเธรดอย่างถูกต้อง แต่อย่าใช้สิ่งต่อไปนี้ (มันจะเป็นปัญหาคอขวดด้านประสิทธิภาพ!):public final class MySingleton {
private static MySingleton instance;
private MySingleton() {
// singleton
}
public static synchronized MySingleton getInstance() {
if (instance == null) {
instance = new MySingleton();
}
return instance;
}
}
หากต้องการการเริ่มต้นแบบ Lazy อย่างแท้จริง การผสมผสานระหว่างสองวิธีนี้ก็จะได้ผล
public final class MySingleton {
private MySingleton() {
// singleton
}
private static final class MySingletonHolder {
static final MySingleton instance = new MySingleton();
}
public static MySingleton getInstance() {
return MySingletonHolder.instance;
}
}
ฤดูใบไม้ผลิ: ตามค่าเริ่มต้น bean จะถูกลงทะเบียนด้วยขอบเขตซิงเกิลตัน ซึ่งหมายความว่าคอนเทนเนอร์จะถูกสร้างขึ้นเพียงอินสแตนซ์เดียวและเชื่อมต่อกับผู้บริโภคทั้งหมด สิ่งนี้ให้ความหมายเช่นเดียวกับซิงเกิลตันปกติ โดยไม่มีข้อจำกัดด้านประสิทธิภาพหรือการเชื่อมโยงใดๆ
ข้อยกเว้น
-
ใช้ข้อยกเว้นที่ตรวจสอบแล้วสำหรับเงื่อนไขที่แก้ไขได้ และข้อยกเว้นรันไทม์สำหรับข้อผิดพลาดในการเขียนโปรแกรม ตัวอย่าง: รับจำนวนเต็มจากสตริง
ไม่ถูกต้อง: NumberFormatException ขยาย RuntimeException ดังนั้นจึงมีวัตถุประสงค์เพื่อระบุข้อผิดพลาดในการเขียนโปรแกรม
-
คุณต้องจัดการข้อยกเว้นในตำแหน่งที่ถูกต้อง ในตำแหน่งที่ถูกต้องในระดับโดเมน
วิธีที่ผิด - ชั้นออบเจ็กต์ข้อมูลไม่รู้ว่าต้องทำอย่างไรเมื่อเกิดข้อยกเว้นฐานข้อมูล
class UserDAO{ public List
getUsers(){ try{ ps = conn.prepareStatement("SELECT * from users"); rs = ps.executeQuery(); //return result }catch(Exception e){ log.error("exception") return null }finally{ //release resources } }} วิธีที่แนะนำ - ชั้นข้อมูลควรสร้างข้อยกเว้นขึ้นใหม่ และส่งต่อความรับผิดชอบในการจัดการข้อยกเว้นหรือไม่ไปยังเลเยอร์ที่ถูกต้อง
=== RECOMMENDED WAY === Data layer should just retrow the exception and transfer the responsability to handle the exception or not to the right layer. class UserDAO{ public List
getUsers(){ try{ ps = conn.prepareStatement("SELECT * from users"); rs = ps.executeQuery(); //return result }catch(Exception e){ throw new DataLayerException(e); }finally{ //release resources } } } -
โดยทั่วไปไม่ควรบันทึกข้อยกเว้น ณ เวลาที่ออก แต่ควรบันทึก ณ เวลาที่มีการประมวลผลจริง ข้อยกเว้นในการบันทึก เมื่อถูกโยนหรือโยนซ้ำ มักจะทำให้ไฟล์บันทึกเต็มไปด้วยสัญญาณรบกวน โปรดทราบว่าการติดตามสแต็กข้อยกเว้นยังคงบันทึกเมื่อมีการส่งข้อยกเว้น
-
รองรับการใช้ข้อยกเว้นมาตรฐาน
-
ใช้ข้อยกเว้นแทนรหัสส่งคืน
อย่าทำสิ่งต่อไปนี้:
// String str = input string
Integer value = null;
try {
value = Integer.valueOf(str);
} catch (NumberFormatException e) {
// non-numeric string
}
if (value == null) {
// handle bad string
} else {
// business logic
}
การใช้งานที่ถูกต้อง:
// String str = input string
// Numeric string with at least one digit and optional leading negative sign
if ( (str != null) && str.matches("-?\\d++") ) {
Integer value = Integer.valueOf(str);
// business logic
} else {
// handle bad string
}
เท่ากับและ HashCode
มีหลายประเด็นที่ต้องพิจารณาเมื่อเขียนวิธีการเทียบเท่าวัตถุและแฮชโค้ดที่เหมาะสม เพื่อให้ง่ายต่อการใช้งาน ให้ใช้ java.util.Objects ' เท่ากับและhashpublic final class User {
private final String firstName;
private final String lastName;
private final int age;
...
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (!(o instanceof User)) {
return false;
}
User user = (User) o;
return Objects.equals(getFirstName(), user.getFirstName()) &&
Objects.equals(getLastName(),user.getLastName()) &&
Objects.equals(getAge(), user.getAge());
}
public int hashCode() {
return Objects.hash(getFirstName(),getLastName(),getAge());
}
}
การจัดการทรัพยากร
วิธีปล่อยทรัพยากรอย่างปลอดภัย: คำสั่ง try-with-resourcesช่วยให้มั่นใจได้ว่าทรัพยากรแต่ละรายการจะถูกปิดที่ส่วนท้ายของคำสั่ง อ็อบเจ็กต์ใดๆ ที่ใช้ java.lang.AutoCloseable ซึ่งรวมถึงอ็อบเจ็กต์ทั้งหมดที่ใช้java.io.Closeableสามารถใช้เป็นทรัพยากรได้private doSomething() {
try (BufferedReader br = new BufferedReader(new FileReader(path)))
try {
// business logic
}
}
ใช้ตะขอปิดเครื่อง
ใช้hook การปิดระบบที่ถูกเรียกเมื่อ JVM ปิดระบบอย่างสวยงาม (แต่จะไม่สามารถจัดการกับการขัดจังหวะกะทันหันได้ เช่น เนื่องจากไฟฟ้าดับ) นี่เป็นทางเลือกที่แนะนำแทนที่จะประกาศเมธอดFinalize()ที่จะทำงานเฉพาะเมื่อSystem.runFinalizersOnExit()เป็นจริง (ค่าเริ่มต้นคือเท็จ) .public final class SomeObject {
var distributedLock = new ExpiringGeneralLock ("SomeObject", "shared");
public SomeObject() {
Runtime
.getRuntime()
.addShutdownHook(new Thread(new LockShutdown(distributedLock)));
}
/** Code may have acquired lock across servers */
...
/** Safely releases the distributed lock. */
private static final class LockShutdown implements Runnable {
private final ExpiringGeneralLock distributedLock;
public LockShutdown(ExpiringGeneralLock distributedLock) {
if (distributedLock == null) {
throw new IllegalArgumentException("ExpiringGeneralLock is null");
}
this.distributedLock = distributedLock;
}
public void run() {
if (isLockAlive()) {
distributedLock.release();
}
}
/** @return True if the lock is acquired and has not expired yet. */
private boolean isLockAlive() {
return distributedLock.getExpirationTimeMillis() > System.currentTimeMillis();
}
}
}
อนุญาตให้ทรัพยากรมีความสมบูรณ์ (รวมถึงทรัพยากรหมุนเวียน) โดยการกระจายทรัพยากรระหว่างเซิร์ฟเวอร์ (ซึ่งจะช่วยให้สามารถฟื้นตัวจากการหยุดชะงักกะทันหัน เช่น ไฟฟ้าดับ) ดูโค้ดตัวอย่างด้านบนที่ใช้ ExpiringGeneralLock (การล็อคทั่วไปสำหรับทุกระบบ)
วันเวลา
Java 8 แนะนำ Date-Time API ใหม่ในแพ็คเกจ java.time Java 8 แนะนำ Date-Time API ใหม่เพื่อแก้ไขข้อบกพร่องของ Date-Time API เก่าดังต่อไปนี้: ไม่มีเธรด การออกแบบที่ไม่ดี การจัดการเขตเวลาที่ซับซ้อน ฯลฯความเท่าเทียม
กฎทั่วไป
- ระวังไลบรารีต่อไปนี้ซึ่งไม่ปลอดภัยต่อเธรด ซิงโครไนซ์กับอ็อบเจ็กต์เสมอหากถูกใช้โดยหลายเธรด
- วันที่ ( ไม่เปลี่ยนรูป ) - ใช้ Date-Time API ใหม่ ซึ่งปลอดภัยสำหรับเธรด
- SimpleDateFormat - ใช้ Date-Time API ใหม่ซึ่งมีเธรดที่ปลอดภัย
- ต้องการใช้คลาสjava.util.concurrent.atomicแทนที่จะทำให้ตัวแปรระเหย
- พฤติกรรมของคลาสอะตอมมิกจะชัดเจนมากขึ้นสำหรับนักพัฒนาทั่วไป ในขณะที่ความผันผวนต้องใช้ความเข้าใจเกี่ยวกับโมเดลหน่วยความจำ Java
- คลาสอะตอมิกจะรวม ตัวแปร ที่ระเหยได้ไว้ในอินเทอร์เฟซที่สะดวกยิ่งขึ้น
- ทำความเข้าใจกรณีการใช้งานที่มีความผันผวน อย่าง เหมาะสม (ดูบทความ )
- ใช้เรียกได้
เมื่อจำเป็นต้องมีการตรวจสอบข้อยกเว้น แต่ไม่มีประเภทการคืนสินค้า เนื่องจาก Void ไม่สามารถสร้างอินสแตนซ์ได้ จึงสื่อสารเจตนาและสามารถส่งคืน null ได้อย่าง ปลอดภัย
สตรีม
- java.lang.Threadควรเลิกใช้แล้ว แม้ว่านี่จะไม่ใช่กรณีอย่างเป็นทางการ แต่ในเกือบทุกกรณี แพ็คเกจ java.util.concurrentมอบแนวทางแก้ไขปัญหาที่ชัดเจนยิ่งขึ้น
- การขยาย java.lang.Thread ถือเป็นแนวปฏิบัติที่ไม่ดี - ใช้ Runnableแทนและสร้างเธรดใหม่ด้วยอินสแตนซ์ในตัวสร้าง (กฎการเรียบเรียงอยู่เหนือการสืบทอด)
- ต้องการตัวดำเนินการและเธรดเมื่อจำเป็นต้องมีการประมวลผลแบบขนาน
- ขอแนะนำเสมอให้ระบุโรงงานเธรดที่คุณกำหนดเองเพื่อจัดการการกำหนดค่าของเธรดที่สร้างขึ้น ( รายละเอียดเพิ่มเติม ที่นี่ )
- ใช้ DaemonThreadFactory ใน Executors สำหรับเธรดที่ไม่สำคัญ เพื่อให้สามารถปิดเธรดพูลได้ทันทีเมื่อเซิร์ฟเวอร์ปิดตัวลง ( รายละเอียดเพิ่มเติม ที่นี่ )
this.executor = Executors.newCachedThreadPool((Runnable runnable) -> {
Thread thread = Executors.defaultThreadFactory().newThread(runnable);
thread.setDaemon(true);
return thread;
});
- การซิงโครไนซ์ Java ไม่ช้าอีกต่อไป (55–110 ns) อย่าหลีกเลี่ยงโดยใช้เทคนิคต่างๆ เช่น การล็อคแบบตรวจ สอบซ้ำ
- ต้องการซิงโครไนซ์กับออบเจ็กต์ภายในมากกว่าคลาส เนื่องจากผู้ใช้สามารถซิงโครไนซ์กับคลาส/อินสแตนซ์ของคุณได้
- ซิงค์หลายวัตถุในลำดับเดียวกันเสมอเพื่อหลีกเลี่ยงการหยุดชะงัก
- การซิงโครไนซ์กับคลาสไม่ได้บล็อกการเข้าถึงอ็อบเจ็กต์ภายในโดยธรรมชาติ ใช้การล็อคแบบเดียวกันเสมอเมื่อเข้าถึงทรัพยากร
- โปรดจำไว้ว่าคำสำคัญที่ซิงโครไนซ์ไม่ถือว่าเป็นส่วนหนึ่งของลายเซ็นวิธีการ และดังนั้นจึงจะไม่ได้รับการสืบทอด
- หลีกเลี่ยงการซิงโครไนซ์มากเกินไป ซึ่งอาจส่งผลให้ประสิทธิภาพไม่ดีและการหยุดชะงักได้ ใช้ คำสำคัญที่ซิงโครไนซ์อย่างเคร่งครัดสำหรับส่วนของโค้ดที่จำเป็นต้องมีการซิงโครไนซ์
คอลเลกชัน
- ใช้คอลเลกชันแบบขนาน Java-5 ในโค้ดแบบมัลติเธรดทุกครั้งที่เป็นไปได้ มีความปลอดภัยและมีลักษณะเฉพาะที่ดีเยี่ยม
- หากจำเป็น ให้ใช้ CopyOnWriteArrayList แทน synchronizedList
- ใช้ Collections.unmodifiable list(...) หรือคัดลอกคอลเลกชันเมื่อได้ รับเป็นพารามิเตอร์ไปที่new ArrayList(list) หลีกเลี่ยงการแก้ไขคอลเลกชันในเครื่องจากภายนอกชั้นเรียนของคุณ
- ส่งคืนสำเนาคอลเลกชันของคุณเสมอ โดยหลีกเลี่ยงการแก้ไขรายการของคุณภายนอกด้วยArrayList (list)ใหม่
- แต่ละคอลเลกชั่นจะต้องอยู่ในคลาสที่แยกจากกัน ดังนั้นพฤติกรรมที่เกี่ยวข้องกับคอลเลกชั่นจึงมีหน้าหลักแล้ว (เช่น วิธีการกรอง การใช้กฎกับแต่ละองค์ประกอบ)
เบ็ดเตล็ด
- เลือกแลมบ์ดามากกว่าคลาสที่ไม่ระบุชื่อ
- เลือกการอ้างอิงวิธีการแทนแลมบ์ดา
- ใช้ enums แทนค่าคงที่ int
- หลีกเลี่ยงการใช้ float และ double ถ้าต้องการคำตอบที่ชัดเจน ให้ใช้ BigDecimal เช่น Money แทน
- เลือกประเภทดั้งเดิมมากกว่าชนิดดั้งเดิมชนิดบรรจุกล่อง
- คุณควรหลีกเลี่ยงการใช้ตัวเลขมหัศจรรย์ในโค้ดของคุณ ใช้ค่าคงที่
- อย่าส่งคืนค่า Null สื่อสารกับไคลเอนต์วิธีการของคุณโดยใช้ `ตัวเลือก` เช่นเดียวกับคอลเลกชัน - ส่งคืนอาร์เรย์หรือคอลเลกชันว่าง ไม่ใช่ค่าว่าง
- หลีกเลี่ยงการสร้างวัตถุที่ไม่จำเป็น นำวัตถุกลับมาใช้ใหม่ และหลีกเลี่ยงการล้างข้อมูล GC ที่ไม่จำเป็น
การเริ่มต้นแบบ Lazy
การเริ่มต้น Lazy เป็นการเพิ่มประสิทธิภาพการทำงาน ใช้เมื่อข้อมูลถูกพิจารณาว่า "แพง" ด้วยเหตุผลบางประการ ใน Java 8 เราต้องใช้อินเทอร์เฟซผู้ให้บริการการทำงานสำหรับสิ่งนี้== Thread safe Lazy initialization ===
public final class Lazy {
private volatile T value;
public T getOrCompute(Supplier supplier) {
final T result = value; // Just one volatile read
return result == null ? maybeCompute(supplier) : result;
}
private synchronized T maybeCompute(Supplier supplier) {
if (value == null) {
value = supplier.get();
}
return value;
}
}
Lazy lazyToString= new Lazy<>()
return lazyToString.getOrCompute( () -> "(" + x + ", " + y + ")");
นั่นคือทั้งหมดสำหรับตอนนี้ ฉันหวังว่าข้อมูลนี้จะเป็นประโยชน์!
GO TO FULL VERSION