Try using it in your preferred language.

English

  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar
translation

นี่คือโพสต์ที่แปลด้วย AI

제이온

[Effective Java] รายการ 6. หลีกเลี่ยงการสร้างอ็อบเจ็กต์ที่ไม่จำเป็น

เลือกภาษา

  • ไทย
  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar

สรุปโดย AI ของ durumis

  • การสร้างอินสแตนซ์ String หรือ Boolean โดยใช้คีย์เวิร์ด new เป็นการสิ้นเปลืองหน่วยความจำ ดังนั้นจึงควรประกาศเป็นลิเทอรัล หรือใช้เมธอด Boolean.valueOf()
  • เมธอด String.matches() ใช้การแสดงออกทั่วไป ดังนั้นจึงอาจทำให้ประสิทธิภาพลดลง ควรแคชอินสแตนซ์ Pattern เพื่อนำกลับมาใช้ใหม่
  • ในกรณีที่คืนค่าอ็อบเจ็กต์แบบมุมมอง เช่น เมธอด keySet() การใช้การคัดลอกแบบป้องกันเพื่อคืนค่าอ็อบเจ็กต์ใหม่จะปลอดภัยกว่า

กรณีการสร้างอ็อบเจกต์ที่ไม่จำเป็น

การใช้ new String()

String a = new String("hi");
String b = new String("hi");


สตริง a, b, c ทั้งหมดจะมีสตริง "hi" แต่เนื่องจากที่อยู่ที่สตริงทั้งสามนี้อ้างอิงถึงนั้นต่างกัน จึงเกิดการสิ้นเปลืองที่ต้องจัดสรรหน่วยความจำที่แตกต่างกันสำหรับข้อมูลเดียวกัน


Untitled


ดังนั้น เมื่อประกาศสตริง เราไม่ควรใช้คีย์เวิร์ด new แต่ควรประกาศเป็นลิเทอรัล


String a = "hi";
String b = "hi";


โค้ดข้างต้นใช้เพียงอินสแตนซ์เดียว นอกจากนี้ การใช้วิธีนี้ยังรับประกันว่าทุกโค้ดที่ใช้ลิเทอรัลสตริง "hi" ภายใน JVM เดียวกัน จะใช้オブジェクトเดียวกัน การใช้ลิเทอรัลสตริงนี้เกิดจากลักษณะเฉพาะของพูลค่าคงที่ของ Java


การใช้ new Boolean()

โค้ดข้างต้นสร้างอินสแตนซ์ Boolean ผ่านคอนสตรัคเตอร์ที่รับสตริงเป็นพารามิเตอร์ Boolean มีเพียง true หรือ false เท่านั้น การสร้างอินสแตนซ์ในแต่ละครั้งเป็นการสิ้นเปลืองหน่วยความจำ ดังนั้น การใช้เมธอดแบบคงที่คือ Boolean.valueOf() จะดีกว่า



การใช้ String.matches()

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


public static boolean isRomanNumeral(String s) {
    return s.matches("^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");


แต่ String.matches() เป็นเมธอดที่มีปัญหาในแง่ของประสิทธิภาพ อินสแตนซ์ Pattern สำหรับการแสดงออกปกติที่เมธอดนี้สร้างขึ้นภายใน จะถูกใช้เพียงครั้งเดียวแล้วทิ้งไป ทำให้กลายเป็นเป้าหมายของการรวบรวมขยะอย่างรวดเร็ว แต่ถ้าการแสดงออกปกติใช้ซ้ำบ่อย ค่าใช้จ่ายในการสร้างและทิ้งอินสแตนซ์ Pattern เดียวกันจะเพิ่มขึ้น ดังนั้น ควรแคชอินสแตนซ์ Pattern ไว้ล่วงหน้า และนำกลับมาใช้ใหม่ทุกครั้งที่เรียกใช้เมธอด isRomanNumeral()


public class RomanNumerals {

    private static final Pattern ROMAN = Pattern.compile(
        "^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");

    public static boolean isRomanNumeral(String s) {
        return ROMAN.matcher(s).matches();
    }


หมายเหตุ

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


อะแดปเตอร์ (วิว) เป็นอ็อบเจกต์ที่มอบหมายงานจริงให้กับอ็อบเจกต์หลังและทำหน้าที่เป็นอินเทอร์เฟซที่สอง อะแดปเตอร์ ต้องจัดการกับอ็อบเจกต์หลังเท่านั้น ดังนั้น ควรสร้างอะแดปเตอร์หนึ่งตัวต่ออ็อบเจกต์หลังหนึ่งตัว


ตัวอย่างเช่น เมธอด keySet() ของอินเทอร์เฟซ Map ส่งคืนวิว Set ที่มีทุกคีย์ภายในอ็อบเจกต์ Map ผู้ใช้ อาจคิดว่าจะสร้างอินสแตนซ์ Set ใหม่ทุกครั้งที่เรียกใช้เมธอด keySet() แต่ในความเป็นจริง การใช้งาน JDK แสดงให้เห็นว่า จะส่งคืนอินสแตนซ์ Set แบบเปลี่ยนแปลงได้เดียวกันทุกครั้ง


สาเหตุนี้เนื่องจากแม้ว่าอินสแตนซ์ Set ที่ส่งคืนจะเป็นแบบเปลี่ยนแปลงได้ แต่ฟังก์ชันที่ทำจะเหมือนกันทั้งหมด และอินสแตนซ์ Set ทั้งหมดจะเป็นตัวแทนของอินสแตนซ์ Map ดังนั้น แม้ว่า keySet() จะสร้างวิวอ็อบเจกต์ หลายตัว ก็ไม่มีผลกระทบใดๆ แต่ก็ไม่มีความจำเป็นและไม่เกิดประโยชน์เช่นกัน


public class UsingKeySet {

    public static void main(String[] args) {
        Map menu = new HashMap<>();
        menu.put("Burger", 8);
        menu.put("Pizza", 9);

        Set names1 = menu.keySet();
        Set names2 = menu.keySet();

        names1.remove("Burger");
        System.out.println(names1.size()); // 1
        System.out.println(names2.size()); // 1
    }


ดังนั้น การแก้ไขอินสแตนซ์ names1 จะส่งผลกระทบต่ออินสแตนซ์ names2 เช่นกัน


อย่างไรก็ตาม ในความคิดส่วนตัว ฉันคิดว่าค่าที่ส่งคืนโดยเมธอด keySet() ควรใช้การคัดลอกแบบป้องกัน เพื่อส่งคืนอ็อบเจกต์ใหม่ทุกครั้ง ถ้าอินสแตนซ์ Set ที่รับจากเมธอด keySet() ถูกใช้ในที่อื่น และมีโค้ดที่เปลี่ยนแปลงสถานะของอินสแตนซ์นี้ เราจะไม่สามารถมั่นใจได้ในค่าของอินสแตนซ์ Set และอินสแตนซ์ Map ที่ใช้อยู่


นอกจากนี้ เว้นแต่จะใช้ keySet() บ่อยมาก การสร้างอินเทอร์เฟซ Set ในแต่ละครั้งจะไม่ส่งผลกระทบอย่างร้ายแรงต่อ ประสิทธิภาพ ฉันคิดว่าการสร้างอินเทอร์เฟซ Set เป็นอ็อบเจกต์แบบไม่แปรเปลี่ยนเพื่อให้สามารถบำรุงรักษาได้อย่างมั่นคง จะดีกว่า


การบรรจุอัตโนมัติ

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


public static long sum() {
    Long sum = 0L;
    for (long i = 0; i <= Integer.MAX_VALUE; i++) {
        sum += i;
    }
    return sum;


ในเชิงตรรกะ โค้ดนี้ไม่มีปัญหา แต่ในแง่ของประสิทธิภาพ โค้ดนี้ไม่มีประสิทธิภาพอย่างมาก สาเหตุ เกิดจากประเภทของ sum และประเภทของ i ภายในลูป for


ประเภทของ sum คือ Long และประเภทของ i คือ long ดังนั้น i ซึ่งเป็นประเภท long จะถูกสร้างเป็นอินสแตนซ์ Long ใหม่ทุกครั้งเมื่อเพิ่มเข้าไปใน sum ขณะที่ลูปทำงาน ผลลัพธ์คือ ควรใช้ประเภทพื้นฐานมากกว่าประเภท wrapper และควรระมัดระวัง เพื่อไม่ให้การบรรจุอัตโนมัติที่ไม่ต้องการถูกใช้


สิ่งที่ไม่ควรเข้าใจผิด

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


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


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


แหล่งที่มา

제이온
제이온
제이온
제이온
[Effective Java] รายการ 5: ใช้การฉีดการพึ่งพาแทนการระบุทรัพยากร หากคลาสพึ่งพาทรัพยากรภายนอก การใช้ซิงเกิลตันและคลาสยูทิลิตี้แบบคงที่ไม่ใช่ความคิดที่ดี การฉีดการพึ่งพาช่วยปรับปรุงความยืดหยุ่น การนำกลับมาใช้ใหม่และความสะดวกในการทดสอบของคลาส และการใช้รูปแบบวิธีการของโรงงานทำให้การฉีดการพึ่งพา มีประสิทธิภาพมากขึ้น

28 เมษายน 2567

[Effective Java] รายการที่ 2. พิจารณาตัวสร้างหากมีพารามิเตอร์มากมาย เมื่อสร้างวัตถุที่มีพารามิเตอร์มากมาย การใช้รูปแบบตัวสร้างจะช่วยให้คุณเขียนโค้ดได้ชัดเจนและอ่านง่ายขึ้น สร้างวัตถุตัวสร้างด้วยพารามิเตอร์ที่จำเป็น และตั้งค่าพารามิเตอร์ทางเลือกด้วยเมธอด setter จากนั้นเรียกใช้เมธอด build() เพื่อทำให้วัตถุเสร็จสมบูรณ์ รูปแบ

27 เมษายน 2567

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

28 เมษายน 2567

วิธีที่ Rust ป้องกันบั๊กแบบพร้อมกัน Rust เป็นภาษาที่ทรงพลังในการแก้ปัญหาความท้าทายของการเขียนโปรแกรมแบบพร้อมกัน ระบบประเภทและแบบจำลองการเป็นเจ้าของทำให้การส่งผ่านและการแชร์ข้อมูลระหว่างเธรดปลอดภัย Mutex, Channel, Atomic และรูปแบบความแปรปรวนภายในอื่น ๆ ช่วยให้คุณกำหนดและใช้ตัวแปรที่แชร์ได้อย
곽경직
곽경직
곽경직
곽경직
곽경직

28 มีนาคม 2567

[ไม่มีพื้นฐานทางวิศวกรรมคอมพิวเตอร์ การอยู่รอดในฐานะนักพัฒนา] 14. สรุปเนื้อหาการสัมภาษณ์ทางเทคนิคที่นักพัฒนาหน้าใหม่ถามบ่อย คู่มือเตรียมตัวสัมภาษณ์งานเทคนิคสำหรับนักพัฒนาหน้าใหม่ บทความนี้จะอธิบายแนวคิดที่มักปรากฏใน การสัมภาษณ์งาน เช่น พื้นที่หน่วยความจำหลัก โครงสร้างข้อมูล RDBMS และ NoSQL การเขียนโปรแกรมเชิงโครงสร้างและเชิงวัตถุ การโอเวอร์ไรด์และการโอเวอร์โหลด อัลกอริทึมการเป
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

3 เมษายน 2567

แนวคิดการปรับปรุงโปรแกรมซื้อขายอัตโนมัติ บทความนี้เสนอแนวคิดการปรับปรุงฟังก์ชันของโปรแกรมการซื้อขายแบบกริดอัตโนมัติ โดยมีการแนะนำการจัดการเหตุการณ์สำคัญ การจัดการตรรกะการลงทุน และการเพิ่มฟังก์ชัน Short Position เป็นต้น โดยเฉพาะฟังก์ชันการถือครองจะช่วยให้ผู้ใช้สามารถซื้อในช่วงเวลาที่เหมาะสมในช่วง
(로또 사는 아빠) 살림 하는 엄마
(로또 사는 아빠) 살림 하는 엄마
(로또 사는 아빠) 살림 하는 엄마
(로또 사는 아빠) 살림 하는 엄마
(로또 사는 아빠) 살림 하는 엄마

21 เมษายน 2567

[Javascript] โครงสร้างของวัตถุ (V8) วัตถุของ JavaScript ในเครื่องยนต์ V8 ถูกแปลงเป็น Fast mode ที่ปรับให้เหมาะสมเหมือนโครงสร้างข้อมูลตามสถานะและ Dictionary mode ที่ทำงานเป็นแฮชแมป Fast mode เร็วเนื่องจากคีย์และค่าอยู่ในรูปแบบคงที่เกือบทั้งหมด แต่เมื่อมีการเพิ่มคีย์ใหม่หรือดำเนินการลบองค์ประ
곽경직
곽경직
곽경직
곽경직
곽경직

18 มีนาคม 2567

[การสอบช่างฝีมือระดับสูงสาขาโลหะวิทยา] 39 ครั้ง การแก้ปัญหา บล็อกโพสต์นี้ครอบคลุมเนื้อหาพื้นฐานเกี่ยวกับสมบัติเชิงกลของวัสดุ การอบชุบความร้อน วิธีการทดสอบ และการตรวจสอบแบบไม่ทำลาย บทความนี้ได้อธิบายแนวคิดและคำศัพท์ต่างๆ เช่น ความต้านทานแรงดึง ความแข็ง การชุบแข็งด้วยคาร์บอน การทดสอบการปล่อยคลื่นเสียง เป็นต้น
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi

24 เมษายน 2567

[Concurrency] Atomic Operation: Memory Fence และ Memory Ordering บล็อกโพสต์นี้จะอธิบายวิธีการพิจารณาลำดับหน่วยความจำใน Atomic Operations และความสำคัญของตัวเลือก Ordering ตัวเลือก Ordering ที่หลากหลาย เช่น Relaxed, Acquire, Release, AcqRel และ SecCst จะถูกอธิบายพร้อมกับข้อดีข้อเสีย และข้อควรระวังในการใช้งานพร้อมกับตัวอย
곽경직
곽경직
곽경직
곽경직
곽경직

12 เมษายน 2567