มีวิธีที่สั้นและไพเราะในการสร้าง a List<Integer>
หรืออาจเป็น Integer[]
หรือint[]
ด้วยค่าลำดับจากค่าบางstart
ค่าเป็นend
ค่าหนึ่ง?
นั่นคือสิ่งที่สั้นกว่า แต่เทียบเท่ากับ1สิ่งต่อไปนี้:
void List<Integer> makeSequence(int begin, int end) {
List<Integer> ret = new ArrayList<>(end - begin + 1);
for (int i=begin; i<=end; i++) {
ret.add(i);
}
return ret;
}
ฝรั่งใช้ก็ใช้ได้
ปรับปรุง:
การวิเคราะห์ประสิทธิภาพ
เนื่องจากคำถามนี้ได้รับคำตอบที่ดีหลายประการทั้งการใช้ Java 8 ดั้งเดิมและไลบรารีของบุคคลที่สามฉันจึงคิดว่าจะทดสอบประสิทธิภาพของโซลูชันทั้งหมด
การทดสอบครั้งแรกเป็นการทดสอบการสร้างรายการองค์ประกอบ 10 รายการ[1..10]
โดยใช้วิธีการต่อไปนี้:
- classicArrayList : รหัสที่ให้ไว้ข้างต้นในคำถามของฉัน (และโดยพื้นฐานแล้วเหมือนกับคำตอบของ adarshr)
- eclipseCollections : รหัสที่ระบุในคำตอบของ Donaldด้านล่างโดยใช้ Eclipse Collections 8.0
- guavaRange : รหัสที่ระบุในคำตอบของ davebด้านล่าง ในทางเทคนิคสิ่งนี้ไม่ได้สร้าง
List<Integer>
แต่เป็นContiguousSet<Integer>
- แต่เนื่องจากมันใช้งานตามIterable<Integer>
ลำดับส่วนใหญ่จึงใช้ได้กับวัตถุประสงค์ของฉัน - intStreamRange : รหัสที่ระบุในคำตอบของ Vladimirด้านล่างซึ่งใช้
IntStream.rangeClosed()
- ซึ่งเปิดตัวใน Java 8 - streamIterate : รหัสที่ระบุในคำตอบของ Catalinด้านล่างซึ่งใช้
IntStream
ฟังก์ชันการทำงานที่แนะนำใน Java 8
นี่คือผลลัพธ์ในการดำเนินการกิโลวัตต์ต่อวินาที (ตัวเลขที่สูงกว่าจะดีกว่า) สำหรับรายการทั้งหมดข้างต้นพร้อมรายการขนาด 10:
... และอีกครั้งสำหรับรายการขนาด 10,000:
แผนภูมิสุดท้ายนั้นถูกต้อง - โซลูชันอื่นที่ไม่ใช่ Eclipse และ Guava นั้นช้าเกินไปที่จะได้รับแถบพิกเซลเดียว! โซลูชันที่รวดเร็วนั้นเร็วกว่าที่เหลือ10,000 ถึง 20,000 เท่า
สิ่งที่เกิดขึ้นที่นี่แน่นอนว่าโซลูชัน guava และ eclipse ไม่ได้สร้างรายการองค์ประกอบ 10,000 ชนิดใด ๆ - พวกมันเป็นเพียงเครื่องห่อขนาดคงที่รอบจุดเริ่มต้นและจุดสิ้นสุด แต่ละองค์ประกอบถูกสร้างขึ้นตามความจำเป็นในระหว่างการทำซ้ำ เนื่องจากเราไม่ได้ทำซ้ำในการทดสอบนี้ค่าใช้จ่ายจึงรอการตัดบัญชี โซลูชันอื่น ๆ ทั้งหมดทำให้รายการทั้งหมดเป็นจริงในหน่วยความจำและจ่ายราคาหนักในเกณฑ์มาตรฐานการสร้างเท่านั้น
มาทำบางสิ่งที่เป็นจริงมากขึ้นและทำซ้ำบนจำนวนเต็มทั้งหมดรวมเข้าด้วยกัน ดังนั้นในกรณีของIntStream.rangeClosed
ตัวแปรเกณฑ์มาตรฐานจะมีลักษณะดังนี้:
@Benchmark
public int intStreamRange() {
List<Integer> ret = IntStream.rangeClosed(begin, end).boxed().collect(Collectors.toList());
int total = 0;
for (int i : ret) {
total += i;
}
return total;
}
ที่นี่รูปภาพเปลี่ยนไปมากแม้ว่าโซลูชันที่ไม่เป็นรูปธรรมจะยังคงเร็วที่สุด นี่คือความยาว = 10:
... และความยาว = 10,000:
การวนซ้ำที่ยาวนานในหลาย ๆ องค์ประกอบทำให้หลาย ๆ อย่างมีมากขึ้น แต่คราสและฝรั่งยังคงเร็วกว่าสองเท่าแม้ในการทดสอบ 10,000 องค์ประกอบ
ดังนั้นหากคุณต้องการจริงๆList<Integer>
คอลเลกชัน eclipse ดูเหมือนจะเป็นทางเลือกที่ดีที่สุด - แต่แน่นอนว่าถ้าคุณใช้สตรีมในแบบเนทีฟมากขึ้น (เช่นลืม.boxed()
และลดโดเมนดั้งเดิม) คุณอาจจะจบลงเร็วกว่าสิ่งเหล่านี้ทั้งหมด สายพันธุ์
1บางทีอาจมีข้อยกเว้นในการจัดการข้อผิดพลาดเช่นถ้าend
< begin
หรือขนาดเกินขีด จำกัด ของการนำไปใช้งานหรือ JVM บางส่วน (เช่นอาร์เรย์ที่ใหญ่กว่า2^31-1
.