ดังที่คนอื่น ๆ พูดไว้ Iterable สามารถถูกเรียกได้หลายครั้งและส่งคืน Iterator ที่สดใหม่ในการโทรแต่ละครั้ง Iterator ใช้เพียงครั้งเดียว ดังนั้นพวกเขาจึงมีความเกี่ยวข้อง แต่ให้บริการตามวัตถุประสงค์ที่แตกต่างกัน อย่างไรก็ตามเฉื่อยชาวิธี "กะทัดรัดสำหรับ" ทำงานได้เฉพาะกับ iterable
สิ่งที่ฉันจะอธิบายด้านล่างนี้เป็นวิธีหนึ่งที่จะได้ผลดีที่สุดของทั้งสองโลก - คืนค่า Iterable (สำหรับไวยากรณ์ที่ดีกว่า) ถึงแม้ว่าลำดับของข้อมูลที่อยู่ข้างนอกจะเป็นแบบครั้งเดียวก็ตาม
เคล็ดลับคือการคืนการใช้งานแบบไม่ระบุชื่อของ Iterable ที่ทำให้เกิดการทำงานจริง ดังนั้นแทนที่จะทำงานที่สร้างลำดับหนึ่งครั้งแล้วคืนค่า Iterator กลับมาคุณจะส่งคืน Iterable ซึ่งทุกครั้งที่มีการเข้าถึงงานจะทำซ้ำงานนั้น ที่อาจดูเหมือนสิ้นเปลือง แต่บ่อยครั้งที่คุณจะเรียก Iterable เพียงครั้งเดียวและแม้ว่าคุณจะเรียกมันหลายครั้งก็ยังมีความหมายที่สมเหตุสมผล (ซึ่งแตกต่างจากเสื้อคลุมเรียบง่ายที่ทำให้ Iterator ล้มเหลวถ้าใช้สองครั้ง)
ตัวอย่างเช่นสมมติว่าฉันมี DAO ที่ให้ชุดของวัตถุจากฐานข้อมูลและฉันต้องการให้การเข้าถึงผ่านทาง iterator (เช่นเพื่อหลีกเลี่ยงการสร้างวัตถุทั้งหมดในหน่วยความจำหากไม่จำเป็น) ตอนนี้ฉันสามารถคืนค่าตัววนซ้ำได้ แต่นั่นทำให้การใช้ค่าที่ส่งคืนในลูปน่าเกลียด ดังนั้นแทนที่ฉันห่อทุกอย่างในอานนท์ Iterable:
class MetricDao {
...
/**
* @return All known metrics.
*/
public final Iterable<Metric> loadAll() {
return new Iterable<Metric>() {
@Override
public Iterator<Metric> iterator() {
return sessionFactory.getCurrentSession()
.createQuery("from Metric as metric")
.iterate();
}
};
}
}
สิ่งนี้สามารถใช้ในรหัสดังนี้:
class DaoUser {
private MetricDao dao;
for (Metric existing : dao.loadAll()) {
// do stuff here...
}
}
ซึ่งให้ฉันใช้คอมแพคสำหรับลูปในขณะที่ยังคงใช้หน่วยความจำเพิ่มเติม
วิธีนี้คือ "สันหลังยาว" - งานไม่ได้ทำเมื่อมีการร้องขอ Iterable แต่ต่อมาเมื่อมีการทำซ้ำเนื้อหา - และคุณต้องระวังผลที่ตามมา ในตัวอย่างที่มี DAO ซึ่งหมายถึงการวนซ้ำผลลัพธ์ภายในธุรกรรมฐานข้อมูล
ดังนั้นจึงมีข้อแม้ต่าง ๆ แต่ยังคงเป็นสำนวนที่มีประโยชน์ในหลายกรณี