JavaRush /จาวาบล็อก /Random-TH /คอฟฟี่เบรค #56 คู่มือฉบับย่อเกี่ยวกับแนวทางปฏิบัติที่ดีที...

คอฟฟี่เบรค #56 คู่มือฉบับย่อเกี่ยวกับแนวทางปฏิบัติที่ดีที่สุดใน Java

เผยแพร่ในกลุ่ม
ที่มา: DZone คู่มือนี้ประกอบด้วยแนวทางปฏิบัติ Java ที่ดีที่สุดและการอ้างอิงเพื่อปรับปรุงความสามารถในการอ่านและความน่าเชื่อถือของโค้ดของคุณ นักพัฒนามีหน้าที่รับผิดชอบใหญ่ในการตัดสินใจที่ถูกต้องทุกวัน และสิ่งที่ดีที่สุดที่สามารถช่วยพวกเขาตัดสินใจได้ถูกต้องก็คือประสบการณ์ และถึงแม้ไม่ใช่ทุกคนจะมีประสบการณ์มากมายในการพัฒนาซอฟต์แวร์ แต่ทุกคนก็สามารถใช้ประสบการณ์ของผู้อื่นได้ ฉันได้เตรียมคำแนะนำบางส่วนที่ได้รับจากประสบการณ์การใช้งาน Java ไว้สำหรับคุณแล้ว ฉันหวังว่าสิ่งเหล่านี้จะช่วยคุณปรับปรุงความสามารถในการอ่านและความน่าเชื่อถือของโค้ด Java ของคุณคอฟฟี่เบรค #56  คู่มือฉบับย่อเกี่ยวกับแนวทางปฏิบัติที่ดีที่สุดใน Java - 1

หลักการเขียนโปรแกรม

อย่าเขียนโค้ดที่ใช้งานได้จริง พยายามเขียนโค้ดที่สามารถบำรุงรักษาได้ไม่ใช่แค่คุณเท่านั้น แต่โดยใครก็ตามที่อาจลงเอยด้วยการพัฒนาซอฟต์แวร์ในอนาคต Developer ใช้เวลา 80% ในการอ่านโค้ด และ 20% ในการเขียนและทดสอบโค้ด ดังนั้นควรเน้นที่การเขียนโค้ดที่อ่านง่าย รหัสของคุณไม่ควรต้องมีความคิดเห็นเพื่อให้ใครก็ตามเข้าใจว่ามันทำอะไร ในการเขียน Code ที่ดีนั้น มีหลักการเขียนโปรแกรมมากมายที่เราสามารถใช้เป็นแนวทางได้ ด้านล่างนี้ฉันจะแสดงรายการที่สำคัญที่สุด
  • • KISS – ย่อมาจาก “Keep It Simple, Stupid” คุณอาจสังเกตเห็นว่านักพัฒนาในช่วงเริ่มต้นของการเดินทางพยายามใช้การออกแบบที่ซับซ้อนและคลุมเครือ
  • • แห้ง - “อย่าพูดซ้ำตัวเอง” พยายามหลีกเลี่ยงการทำซ้ำใดๆ แทนที่จะรวมไว้ในส่วนเดียวของระบบหรือวิธีการ
  • YAGNI - “คุณไม่ต้องการมันหรอก” หากคุณเริ่มถามตัวเองทันทีว่า “แล้วจะเพิ่มอะไรอีก (ฟีเจอร์ โค้ด ฯลฯ) ล่ะ?” คุณอาจต้องพิจารณาว่าคุ้มที่จะเพิ่มเข้าไปจริงๆ หรือไม่
  • ทำความสะอาดโค้ดแทนโค้ดอัจฉริยะ - พูดง่ายๆ ก็คือปล่อยอัตตาของคุณไว้ที่ประตูและลืมการเขียนโค้ดอัจฉริยะไปเลย คุณต้องการโค้ดที่สะอาด ไม่ใช่โค้ดอัจฉริยะ
  • หลีกเลี่ยงการเพิ่มประสิทธิภาพก่อนเวลาอันควร - ปัญหาของการเพิ่มประสิทธิภาพก่อนเวลาอันควรคือคุณไม่มีทางรู้ได้เลยว่าปัญหาคอขวดจะอยู่ที่จุดใดในโปรแกรมจนกว่าจะปรากฏขึ้น
  • ความรับผิดชอบเดี่ยว - แต่ละคลาสหรือโมดูลในโปรแกรมควรให้ความสำคัญกับฟังก์ชันการทำงานเฉพาะเพียงเล็กน้อยเท่านั้น
  • องค์ประกอบมากกว่าการสืบทอดการใช้งาน - ออบเจ็กต์ที่มีพฤติกรรมที่ซับซ้อนควรมีอินสแตนซ์ของออบเจ็กต์ที่มีพฤติกรรมเป็นรายบุคคล แทนที่จะสืบทอดคลาสและเพิ่มพฤติกรรมใหม่
  • ยิมนาสติกแบบวัตถุ เป็นแบบฝึกหัดการเขียนโปรแกรมที่ออกแบบ มาเป็นชุดกฎ 9 ข้อ
  • ล้มเหลวเร็ว หยุดเร็ว - หลักการนี้หมายถึงการหยุดการทำงานปัจจุบันเมื่อเกิดข้อผิดพลาดที่ไม่คาดคิด การปฏิบัติตามหลักการนี้นำไปสู่การทำงานที่มีเสถียรภาพมากขึ้น

แพ็คเกจ

  1. จัดลำดับความสำคัญของการจัดโครงสร้างบรรจุภัณฑ์ตามสาขาวิชามากกว่าตามระดับเทคนิค
  2. ชอบเลย์เอาต์ที่ส่งเสริมการห่อหุ้มและการซ่อนข้อมูลเพื่อป้องกันการใช้ในทางที่ผิด แทนที่จะจัดชั้นเรียนด้วยเหตุผลทางเทคนิค
  3. ปฏิบัติต่อแพ็คเกจราวกับว่ามี API ที่ไม่เปลี่ยนรูป - อย่าเปิดเผยกลไกภายใน (คลาส) ที่มีไว้สำหรับการประมวลผลภายในเท่านั้น
  4. อย่าเปิดเผยคลาสที่มีวัตถุประสงค์เพื่อใช้ภายในแพ็คเกจเท่านั้น

ชั้นเรียน

คงที่

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

มรดก

  1. เลือกองค์ประกอบมากกว่าการสืบทอด
  2. อย่าตั้งค่าฟิลด์ที่มีการป้องกัน ให้ระบุวิธีการเข้าถึงที่ปลอดภัย แทน
  3. หากตัวแปรคลาสสามารถทำเครื่องหมายเป็นFinalได้ ให้ทำเช่นนั้น
  4. หากไม่คาดหวังการ สืบทอดให้ทำให้คลาสเป็นขั้นสุดท้าย
  5. ทำเครื่องหมายวิธีการเป็นขั้นตอนสุดท้ายหากไม่คาดหวังว่าคลาสย่อยจะได้รับอนุญาตให้แทนที่วิธีการนั้น
  6. หากไม่จำเป็นต้องใช้ตัวสร้าง อย่าสร้างตัวสร้างเริ่มต้นโดยไม่มีตรรกะในการนำไปใช้งาน Java จะให้คอนสตรัคเตอร์เริ่มต้นโดยอัตโนมัติหากไม่มีการระบุ

อินเทอร์เฟซ

  1. อย่าใช้อินเทอร์เฟซของรูปแบบค่าคงที่เนื่องจากจะทำให้คลาสสามารถนำไปใช้และทำให้ API เสียหายได้ ใช้คลาสคงที่แทน สิ่งนี้มีประโยชน์เพิ่มเติมในการช่วยให้คุณสามารถเริ่มต้นออบเจ็กต์ที่ซับซ้อนมากขึ้นในบล็อกแบบคงที่ (เช่น การเติมคอลเลกชัน)
  2. หลีกเลี่ยงการใช้อินเทอร์เฟซมากเกินไป
  3. การมีคลาสเดียวที่ใช้อินเทอร์เฟซอาจนำไปสู่การใช้อินเทอร์เฟซมากเกินไปและก่อให้เกิดผลเสียมากกว่าผลดี
  4. "โปรแกรมสำหรับอินเทอร์เฟ ซไม่ใช่การใช้งาน" ไม่ได้หมายความว่าคุณควรรวมคลาสโดเมนแต่ละคลาสของคุณเข้ากับอินเทอร์เฟซที่เหมือนกันไม่มากก็น้อย การทำเช่นนี้คุณจะทำลายYAGNI
  5. รักษาอินเทอร์เฟซให้เล็กและเฉพาะเจาะจงอยู่เสมอ เพื่อให้ลูกค้าทราบเฉพาะวิธีการที่พวกเขาสนใจเท่านั้น ตรวจสอบ ISP จาก SOLID

ผู้เข้ารอบสุดท้าย

  1. อ็อบเจ็กต์#finalize()ควรใช้อย่างรอบคอบและเป็นเพียงวิธีการป้องกันความล้มเหลวเมื่อทำการล้างทรัพยากร (เช่น การปิดไฟล์) จัดเตรียมวิธีการล้างข้อมูลที่ชัดเจนเสมอ (เช่นclose() )
  2. ในลำดับชั้นการสืบทอด ให้เรียก parent's Finalize()ในtry block เสมอ การล้างข้อมูลในชั้น เรียนควรอยู่ใน บล็อก สุดท้าย
  3. หากไม่ได้เรียกวิธีการล้างข้อมูลอย่างชัดเจนและโปรแกรมปิดขั้นสุดท้ายปิดทรัพยากร ให้บันทึกข้อผิดพลาดนี้
  4. หากไม่มีตัวบันทึก ให้ใช้ตัวจัดการข้อยกเว้นของเธรด (ซึ่งท้ายที่สุดจะผ่านข้อผิดพลาดมาตรฐานที่บันทึกไว้ในบันทึก)

กฎทั่วไป

งบ

การยืนยัน ซึ่งมักจะอยู่ในรูปแบบของการตรวจสอบเงื่อนไขเบื้องต้น บังคับใช้สัญญา "ล้มเหลวอย่างรวดเร็ว หยุดอย่างรวดเร็ว" ควรใช้กันอย่างแพร่หลายเพื่อระบุข้อผิดพลาดในการเขียนโปรแกรมให้ใกล้เคียงกับสาเหตุมากที่สุด สภาพวัตถุ:
  • • วัตถุไม่ควรถูกสร้างขึ้นหรือทำให้อยู่ในสถานะที่ไม่ถูกต้อง
  • • ใน Constructors และ Methods ให้อธิบายและบังคับใช้สัญญาโดยใช้การทดสอบเสมอ
  • • ควรหลีกเลี่ยง การยืนยันคีย์เวิร์ด Java เนื่องจากสามารถปิดการใช้งานได้ และโดยปกติจะเป็นโครงสร้างที่เปราะบาง
  • • ใช้ คลาสยูทิลิตี้Assertionsเพื่อหลีกเลี่ยง เงื่อนไข if-else แบบละเอียด สำหรับการตรวจสอบเงื่อนไขเบื้องต้น

ยาสามัญ

คำอธิบายโดยละเอียดโดยละเอียดเต็มรูปแบบ มีอยู่ในJava Generics FAQ ด้านล่างนี้เป็นสถานการณ์ทั่วไปที่นักพัฒนาซอฟต์แวร์ควรทราบ
  1. เมื่อใดก็ตามที่เป็นไปได้ ควรใช้การอนุมานประเภทแทนที่จะส่งคืนคลาส/อินเทอร์เฟซพื้นฐาน:

    // MySpecialObject o = MyObjectFactory.getMyObject();
    public  T getMyObject(int type) {
    return (T) factory.create(type);
    }

  2. หากไม่สามารถกำหนดประเภทได้โดยอัตโนมัติ ให้อินไลน์

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

  3. สัญลักษณ์แทน:

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

    1. ใครๆ ก็รักPECS ! ( ผู้ผลิต-ขยาย, ผู้บริโภค-ซุปเปอร์ )
    2. ใช้Fooสำหรับโปรดิวเซอร์ T.
    3. ใช้ 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 จะถูกลงทะเบียนด้วยขอบเขตซิงเกิลตัน ซึ่งหมายความว่าคอนเทนเนอร์จะถูกสร้างขึ้นเพียงอินสแตนซ์เดียวและเชื่อมต่อกับผู้บริโภคทั้งหมด สิ่งนี้ให้ความหมายเช่นเดียวกับซิงเกิลตันปกติ โดยไม่มีข้อจำกัดด้านประสิทธิภาพหรือการเชื่อมโยงใดๆ

ข้อยกเว้น

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

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

  2. อย่าทำสิ่งต่อไปนี้:

    // 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
    }
  3. คุณต้องจัดการข้อยกเว้นในตำแหน่งที่ถูกต้อง ในตำแหน่งที่ถูกต้องในระดับโดเมน

    วิธีที่ผิด - ชั้นออบเจ็กต์ข้อมูลไม่รู้ว่าต้องทำอย่างไรเมื่อเกิดข้อยกเว้นฐานข้อมูล

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

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

  5. รองรับการใช้ข้อยกเว้นมาตรฐาน

  6. ใช้ข้อยกเว้นแทนรหัสส่งคืน

เท่ากับและ HashCode

มีหลายประเด็นที่ต้องพิจารณาเมื่อเขียนวิธีการเทียบเท่าวัตถุและแฮชโค้ดที่เหมาะสม เพื่อให้ง่ายต่อการใช้งาน ให้ใช้ java.util.Objects ' เท่ากับและhash
public 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 เก่าดังต่อไปนี้: ไม่มีเธรด การออกแบบที่ไม่ดี การจัดการเขตเวลาที่ซับซ้อน ฯลฯ

ความเท่าเทียม

กฎทั่วไป

  1. ระวังไลบรารีต่อไปนี้ซึ่งไม่ปลอดภัยต่อเธรด ซิงโครไนซ์กับอ็อบเจ็กต์เสมอหากถูกใช้โดยหลายเธรด
  2. วันที่ ( ไม่เปลี่ยนรูป ) - ใช้ Date-Time API ใหม่ ซึ่งปลอดภัยสำหรับเธรด
  3. SimpleDateFormat - ใช้ Date-Time API ใหม่ซึ่งมีเธรดที่ปลอดภัย
  4. ต้องการใช้คลาสjava.util.concurrent.atomicแทนที่จะทำให้ตัวแปรระเหย
  5. พฤติกรรมของคลาสอะตอมมิกจะชัดเจนมากขึ้นสำหรับนักพัฒนาทั่วไป ในขณะที่ความผันผวนต้องใช้ความเข้าใจเกี่ยวกับโมเดลหน่วยความจำ Java
  6. คลาสอะตอมิกจะรวม ตัวแปร ที่ระเหยได้ไว้ในอินเทอร์เฟซที่สะดวกยิ่งขึ้น
  7. ทำความเข้าใจกรณีการใช้งานที่มีความผันผวน อย่าง เหมาะสม (ดูบทความ )
  8. ใช้เรียกได้ เมื่อจำเป็นต้องมีการตรวจสอบข้อยกเว้น แต่ไม่มีประเภทการคืนสินค้า เนื่องจาก Void ไม่สามารถสร้างอินสแตนซ์ได้ จึงสื่อสารเจตนาและสามารถส่งคืน null ได้อย่าง ปลอดภัย

สตรีม

  1. java.lang.Threadควรเลิกใช้แล้ว แม้ว่านี่จะไม่ใช่กรณีอย่างเป็นทางการ แต่ในเกือบทุกกรณี แพ็คเกจ java.util.concurrentมอบแนวทางแก้ไขปัญหาที่ชัดเจนยิ่งขึ้น
  2. การขยาย java.lang.Thread ถือเป็นแนวปฏิบัติที่ไม่ดี - ใช้ Runnableแทนและสร้างเธรดใหม่ด้วยอินสแตนซ์ในตัวสร้าง (กฎการเรียบเรียงอยู่เหนือการสืบทอด)
  3. ต้องการตัวดำเนินการและเธรดเมื่อจำเป็นต้องมีการประมวลผลแบบขนาน
  4. ขอแนะนำเสมอให้ระบุโรงงานเธรดที่คุณกำหนดเองเพื่อจัดการการกำหนดค่าของเธรดที่สร้างขึ้น ( รายละเอียดเพิ่มเติม ที่นี่ )
  5. ใช้ DaemonThreadFactory ใน Executors สำหรับเธรดที่ไม่สำคัญ เพื่อให้สามารถปิดเธรดพูลได้ทันทีเมื่อเซิร์ฟเวอร์ปิดตัวลง ( รายละเอียดเพิ่มเติม ที่นี่ )
this.executor = Executors.newCachedThreadPool((Runnable runnable) -> {
   Thread thread = Executors.defaultThreadFactory().newThread(runnable);
   thread.setDaemon(true);
   return thread;
});
  1. การซิงโครไนซ์ Java ไม่ช้าอีกต่อไป (55–110 ns) อย่าหลีกเลี่ยงโดยใช้เทคนิคต่างๆ เช่น การล็อคแบบตรวจ สอบซ้ำ
  2. ต้องการซิงโครไนซ์กับออบเจ็กต์ภายในมากกว่าคลาส เนื่องจากผู้ใช้สามารถซิงโครไนซ์กับคลาส/อินสแตนซ์ของคุณได้
  3. ซิงค์หลายวัตถุในลำดับเดียวกันเสมอเพื่อหลีกเลี่ยงการหยุดชะงัก
  4. การซิงโครไนซ์กับคลาสไม่ได้บล็อกการเข้าถึงอ็อบเจ็กต์ภายในโดยธรรมชาติ ใช้การล็อคแบบเดียวกันเสมอเมื่อเข้าถึงทรัพยากร
  5. โปรดจำไว้ว่าคำสำคัญที่ซิงโครไนซ์ไม่ถือว่าเป็นส่วนหนึ่งของลายเซ็นวิธีการ และดังนั้นจึงจะไม่ได้รับการสืบทอด
  6. หลีกเลี่ยงการซิงโครไนซ์มากเกินไป ซึ่งอาจส่งผลให้ประสิทธิภาพไม่ดีและการหยุดชะงักได้ ใช้ คำสำคัญที่ซิงโครไนซ์อย่างเคร่งครัดสำหรับส่วนของโค้ดที่จำเป็นต้องมีการซิงโครไนซ์

คอลเลกชัน

  1. ใช้คอลเลกชันแบบขนาน Java-5 ในโค้ดแบบมัลติเธรดทุกครั้งที่เป็นไปได้ มีความปลอดภัยและมีลักษณะเฉพาะที่ดีเยี่ยม
  2. หากจำเป็น ให้ใช้ CopyOnWriteArrayList แทน synchronizedList
  3. ใช้ Collections.unmodifiable list(...) หรือคัดลอกคอลเลกชันเมื่อได้ รับเป็นพารามิเตอร์ไปที่new ArrayList(list) หลีกเลี่ยงการแก้ไขคอลเลกชันในเครื่องจากภายนอกชั้นเรียนของคุณ
  4. ส่งคืนสำเนาคอลเลกชันของคุณเสมอ โดยหลีกเลี่ยงการแก้ไขรายการของคุณภายนอกด้วยArrayList (list)ใหม่
  5. แต่ละคอลเลกชั่นจะต้องอยู่ในคลาสที่แยกจากกัน ดังนั้นพฤติกรรมที่เกี่ยวข้องกับคอลเลกชั่นจึงมีหน้าหลักแล้ว (เช่น วิธีการกรอง การใช้กฎกับแต่ละองค์ประกอบ)

เบ็ดเตล็ด

  1. เลือกแลมบ์ดามากกว่าคลาสที่ไม่ระบุชื่อ
  2. เลือกการอ้างอิงวิธีการแทนแลมบ์ดา
  3. ใช้ enums แทนค่าคงที่ int
  4. หลีกเลี่ยงการใช้ float และ double ถ้าต้องการคำตอบที่ชัดเจน ให้ใช้ BigDecimal เช่น Money แทน
  5. เลือกประเภทดั้งเดิมมากกว่าชนิดดั้งเดิมชนิดบรรจุกล่อง
  6. คุณควรหลีกเลี่ยงการใช้ตัวเลขมหัศจรรย์ในโค้ดของคุณ ใช้ค่าคงที่
  7. อย่าส่งคืนค่า Null สื่อสารกับไคลเอนต์วิธีการของคุณโดยใช้ `ตัวเลือก` เช่นเดียวกับคอลเลกชัน - ส่งคืนอาร์เรย์หรือคอลเลกชันว่าง ไม่ใช่ค่าว่าง
  8. หลีกเลี่ยงการสร้างวัตถุที่ไม่จำเป็น นำวัตถุกลับมาใช้ใหม่ และหลีกเลี่ยงการล้างข้อมูล 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 + ")");
นั่นคือทั้งหมดสำหรับตอนนี้ ฉันหวังว่าข้อมูลนี้จะเป็นประโยชน์!
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION