Java: วิธีที่ดีที่สุดในการวนซ้ำผ่านคอลเล็กชัน (ที่นี่ ArrayList)


99

วันนี้ฉันมีความสุขในการเขียนโค้ดเมื่อฉันไปถึงโค้ดชิ้นหนึ่งที่ฉันใช้ไปแล้วหลายร้อยครั้ง:

การทำซ้ำผ่านคอลเล็กชัน (ที่นี่ ArrayList)

ด้วยเหตุผลบางอย่างฉันดูตัวเลือกการเติมข้อความอัตโนมัติของ Eclipse และทำให้ฉันสงสัยว่า:

ลูปต่อไปนี้ใช้งานได้ดีกว่าลูปอื่น ๆ ในกรณีใดบ้าง

ลูปดัชนีอาร์เรย์คลาสสิก:

for (int i = 0; i < collection.length; i++) {
  type array_element = collection.get(index);
}

Iterator hasNext () / next ():

for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
  type type = (type) iterator.next();   
}

และสิ่งที่ฉันชอบเพราะมันเขียนง่ายมาก:

for (iterable_type iterable_element : collection) {

}

2
เมื่อพูดถึงฉันฉันใช้วงที่ 3 เป็นส่วนใหญ่
Harry Joy

1
สำหรับวิธีที่สองดีกว่าที่จะใช้: for (Iterator<type> iterator = collection.iterator(); iterator.hasNext();) { type type = iterator.next(); }
ไมค์โจนส์

4
อินเทอร์เฟซการรวบรวมไม่มีเมธอด "get" ดังนั้นวิธีแรกจึงเป็นไปไม่ได้เสมอไป
ThePerson

นอกจากนี้ในตัวเลือกแรกสำหรับ 'for loop' ควรเปลี่ยน collection.length เป็น collection.size ()
Vishwathma

คำตอบ:


106

อันแรกมีประโยชน์เมื่อคุณต้องการดัชนีขององค์ประกอบด้วย โดยทั่วไปแล้วสิ่งนี้เทียบเท่ากับอีกสองตัวแปรสำหรับArrayLists แต่จะช้ามากถ้าคุณใช้ไฟล์LinkedList.

อันที่สองมีประโยชน์เมื่อคุณไม่ต้องการดัชนีขององค์ประกอบ แต่อาจต้องนำองค์ประกอบออกเมื่อคุณทำซ้ำ แต่สิ่งนี้มีข้อเสียของการเป็น IMO ที่ละเอียดเกินไปเล็กน้อย

รุ่นที่สามเป็นตัวเลือกที่ฉันชอบเช่นกัน สั้นและใช้ได้กับทุกกรณีที่คุณไม่ต้องการดัชนีใด ๆ หรือตัววนซ้ำพื้นฐาน (เช่นคุณกำลังเข้าถึงองค์ประกอบเท่านั้นไม่ได้ลบออกหรือแก้ไขCollectionด้วยวิธีใด ๆ - ซึ่งเป็นกรณีที่พบบ่อยที่สุด)


3
+1 เอาชนะฉันให้ได้ กำลังจะพูดถึง LinkedList (ไม่ใช่ทุกคน Collectionจะถูกเรียกค้นโดยดัชนี)
The Scrum Meister

ตราบใดที่จำเป็นต้องใช้เพียงแค่องค์ประกอบแบบวนซ้ำคุณควรใช้เวอร์ชันที่ 3 เสมอเนื่องจากการใช้งานมีอยู่แล้วสำหรับคอลเล็กชันและ Sun ที่แตกต่างกันทั้งหมดหรือการใช้งาน JDK ใด ๆ พยายามปรับปรุงประสิทธิภาพมากกว่าทุกองค์ประกอบ
Phani

@Phani: อีกสองสายพันธุ์ยังทำงานกับการใช้งาน JDK ได้เช่นกัน
MAK

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

1
@Phani: AFAIK รูปแบบที่ 3 เป็นเพียงน้ำตาลวากยสัมพันธ์สำหรับรูปแบบที่ 2 (เช่นภายใต้ประทุนตัวแปร foreach ใช้ตัววนซ้ำ) ดังนั้นประโยชน์ด้านประสิทธิภาพใด ๆ ควรมีให้สำหรับทั้งสองรุ่น หลักสูตรเวอร์ชันแรกจะไม่ได้รับประโยชน์ด้านประสิทธิภาพใด ๆ (เช่นหากListนำไปใช้เป็นต้นไม้จริง ๆ แล้วจะช้ากว่า)
MAK

37

ทั้งหมดมีการใช้งานของตัวเอง:

  1. หากคุณสามารถทำซ้ำได้และจำเป็นต้องสำรวจทุกอย่างโดยไม่มีเงื่อนไข:

    สำหรับ (iterable_type iterable_element: collection)

  2. หากคุณสามารถทำซ้ำได้ แต่ต้องการสำรวจตามเงื่อนไข:

    สำหรับ (Iterator iterator = collection.iterator (); iterator.hasNext ();)

  3. หากโครงสร้างข้อมูลไม่สามารถใช้ซ้ำได้:

    สำหรับ (int i = 0; i <collection.length; i ++)


คุณสามารถทำได้เพื่อข้ามเมธอดแรกตามเงื่อนไข: if (iterable_element.some_attribute) {// do something; } else {// ไม่ต้องทำอะไรเลย; }. ถ้าใช่ก็ไม่มีความแตกต่างระหว่างวิธีแรกและวิธีที่สองนอกเหนือจากน้ำตาลที่เป็นประโยค
Thomas Nguyen

1 สามารถสำรวจตามเงื่อนไขได้เช่นเดียวกับที่คนอื่นใช้breakและ / หรือcontinue
arcyqwerty

13

นอกจากนี้ยังมีสตรีม () ของคอลเล็กชันเพิ่มเติมด้วย Java 8

collection.forEach((temp) -> {
            System.out.println(temp);
});

หรือ

collection.forEach(System.out::println);

ข้อมูลเพิ่มเติมเกี่ยวกับสตรีม Java 8 และคอลเล็กชันสำหรับลิงก์สิ่งมหัศจรรย์


4

ไม่มีใคร "ดีกว่า" ไปกว่าคนอื่น ๆ อย่างที่สามคือสำหรับฉันอ่านได้ง่ายกว่า แต่สำหรับคนที่ไม่ใช้ foreaches มันอาจดูแปลก ๆ (พวกเขาอาจชอบแบบแรก) ทั้ง 3 อย่างชัดเจนสำหรับทุกคนที่เข้าใจ Java ดังนั้นให้เลือกสิ่งที่คุณรู้สึกดีกว่าเกี่ยวกับโค้ด

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


2

ตัวเลือกแรกคือประสิทธิภาพที่ดีกว่า (เนื่องจาก ArrayList ใช้อินเทอร์เฟซ RandomAccess) ตาม java doc การใช้งาน List ควรใช้อินเทอร์เฟซ RandomAccess ถ้าสำหรับอินสแตนซ์ทั่วไปของคลาสลูปนี้:

 for (int i=0, n=list.size(); i < n; i++)
     list.get(i);

วิ่งเร็วกว่าลูปนี้:

 for (Iterator i=list.iterator(); i.hasNext(); )
     i.next();

ฉันหวังว่ามันจะช่วยได้ ตัวเลือกแรกจะช้าสำหรับรายการเข้าถึงตามลำดับ


1

นี่คือตัวอย่าง

Query query = em.createQuery("from Student");
             java.util.List list = query.getResultList();
             for (int i = 0; i < list.size(); i++) 
             {

                 student = (Student) list.get(i);
                 System.out.println(student.id  + "  " + student.age + " " + student.name + " " + student.prenom);

             }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.