दिलचस्प पोस्ट
स्थिर और साझा पुस्तकालयों के बीच का अंतर? UIView में पारदर्शी छेद कट स्ट्रिंग में एक यूनिकोड वर्ण को कैसे व्याख्या करना क्या "अपरिभाषित व्यवहार" वास्तव में कुछ * होने की अनुमति देता है? वस्तुओं की क्षैतिज व्यवस्था के साथ WPF ListView? पृष्ठ पुनः लोड पर मैं jqGrid में खोज फ़िल्टर कैसे सुरक्षित रख सकता हूं? कैसे हाइबरनेट HQL परिणामों के साथ प्रकार सुरक्षा चेतावनियों से बचने के लिए? मैं रिमोट जीआईटी शाखा कैसे बदलूंगा? Google मानचित्र v3 – देखने योग्य क्षेत्र और ज़ूम स्तर सीमित करें अजीब जावा व्यवहार टर्नरी ऑपरेटर JavaScript में दो नंबरों के बीच यादृच्छिक संख्या उत्पन्न करें उपयोगकर्ता छवियां – डाटाबेस बनाम फाइलसिस्टम स्टोरेज मैं किसी उपयोगकर्ता द्वारा ऐप्प रनों के बीच आईफोन घड़ी की प्रगति कैसे खोज सकता हूं? विजुअल स्टूडियो 2008 परियोजनाओं के लिए मर्कुरियल। हाग्ग्नोर स्विंग जीयूआई में सफेद स्थान प्रदान करना

जो अधिक कुशल है, प्रत्येक लूप के लिए, या एक इटरेटर?

संग्रह पार करने का सबसे कारगर तरीका कौन सा है?

List<Integer> a = new ArrayList<Integer>(); for (Integer integer : a) { integer.toString(); } 

या

 List<Integer> a = new ArrayList<Integer>(); for (Iterator iterator = a.iterator(); iterator.hasNext();) { Integer integer = (Integer) iterator.next(); integer.toString(); } 

कृपया ध्यान दें, यह इस बात का एक सटीक डुप्लिकेट नहीं है, यह , यह , या यह , हालांकि अंतिम प्रश्न के जवाब में से एक करीब आता है। यह एक धोखा नहीं है, इसका कारण यह है कि इनमें से अधिकतर लूप की तुलना करते हैं, जहां आप कॉल करते get(i) लूप के अंदर, इटरेटर का उपयोग करने के बजाय

जैसा कि मेटा पर सुझाव दिया गया है, मैं इस प्रश्न का उत्तर पोस्ट कर रहा हूं।

Solutions Collecting From Web of "जो अधिक कुशल है, प्रत्येक लूप के लिए, या एक इटरेटर?"

यदि आप सभी मूल्यों को पढ़ने के लिए सिर्फ संग्रह पर भटकते हैं, तो एक इटेटर या लूप सिंटैक्स के लिए नया का उपयोग करने में कोई अंतर नहीं है, क्योंकि नया सिंटैक्स सिर्फ इटरेटर पानी के नीचे का उपयोग करता है।

यदि यद्यपि, आप का अर्थ है कि पुरानी "सी-शैली" लूप लूप:

 for(int i=0; i<list.size(); i++) { Object o = list.get(i); } 

फिर अंतर्निहित डेटा संरचना के आधार पर, लूप या इटरेटर के लिए नया, बहुत अधिक कुशल हो सकता है। इसका कारण यह है कि कुछ डेटा संरचनाओं के लिए, get(i) एक ओ (एन) ऑपरेशन है, जो लूप को एक ओ (एन 2 ) ऑपरेशन बनाता है एक पारंपरिक लिंक्ड सूची ऐसी डेटा संरचना का एक उदाहरण है। सभी iterators एक मौलिक आवश्यकता के रूप में है कि next() एक हे (1) ऑपरेशन होना चाहिए, जिससे लूप हे (एन)

यह सत्यापित करने के लिए कि लूप सिंटैक्स के लिए नए द्वारा इटरेटर का पानी के नीचे उपयोग किया जाता है, निम्नलिखित दो जावा स्निपेट्स से उत्पन्न बाइटटेकोड की तुलना करें। पहले लूप के लिए:

 List<Integer> a = new ArrayList<Integer>(); for (Integer integer : a) { integer.toString(); } // Byte code ALOAD 1 INVOKEINTERFACE java/util/List.iterator()Ljava/util/Iterator; ASTORE 3 GOTO L2 L3 ALOAD 3 INVOKEINTERFACE java/util/Iterator.next()Ljava/lang/Object; CHECKCAST java/lang/Integer ASTORE 2 ALOAD 2 INVOKEVIRTUAL java/lang/Integer.toString()Ljava/lang/String; POP L2 ALOAD 3 INVOKEINTERFACE java/util/Iterator.hasNext()Z IFNE L3 

और दूसरा, इटरेटर:

 List<Integer> a = new ArrayList<Integer>(); for (Iterator iterator = a.iterator(); iterator.hasNext();) { Integer integer = (Integer) iterator.next(); integer.toString(); } // Bytecode: ALOAD 1 INVOKEINTERFACE java/util/List.iterator()Ljava/util/Iterator; ASTORE 2 GOTO L7 L8 ALOAD 2 INVOKEINTERFACE java/util/Iterator.next()Ljava/lang/Object; CHECKCAST java/lang/Integer ASTORE 3 ALOAD 3 INVOKEVIRTUAL java/lang/Integer.toString()Ljava/lang/String; POP L7 ALOAD 2 INVOKEINTERFACE java/util/Iterator.hasNext()Z IFNE L8 

जैसा कि आप देख सकते हैं, उत्पन्न बाइट कोड प्रभावी रूप से समान है, इसलिए किसी भी रूप का उपयोग करने के लिए कोई प्रदर्शन जुर्माना नहीं है। इसलिए, आपको लूप का रूप चुनना चाहिए जो कि आपके लिए सबसे सौंदर्यवादिता से अपील करता है, अधिकांश लोगों के लिए प्रत्येक लूप के लिए होगा, क्योंकि इसमें कम बॉयलरप्लेट कोड है।

अंतर प्रदर्शन में नहीं है, लेकिन क्षमता में है। एक संदर्भ का उपयोग करते समय सीधे एक प्रकार के इटरेटर (उदाहरण के लिए List.iterator () बनाम List.listIterator () का उपयोग करते हुए आपको अधिक शक्ति होती है, हालांकि अधिकांश मामलों में वे एक ही लागू करते हैं)। आपके पास अपने लूप में इटरेटर को संदर्भित करने की भी क्षमता है यह आपको समवर्ती सुधार के बिना अपने संग्रह से आइटम निकालने जैसी चीज़ों को करने की अनुमति देता है।

जैसे

यह ठीक है:

 Set<Object> set = new HashSet<Object>(); // add some items to the set Iterator<Object> setIterator = set.iterator(); while(setIterator.hasNext()){ Object o = setIterator.next(); if(o meets some condition){ setIterator.remove(); } } 

ऐसा नहीं है, क्योंकि यह एक समवर्ती संशोधन अपवाद फेंकता है:

 Set<Object> set = new HashSet<Object>(); // add some items to the set for(Object o : set){ if(o meets some condition){ set.remove(o); } } 

पॉल के स्वयं के जवाब पर विस्तार करने के लिए, उन्होंने यह दर्शाया है कि बाइटकोक उस विशेष संकलक पर समान है (संभवतः सूर्य का जावा?) लेकिन अलग-अलग कंपाइलरों को उसी बाइटकोड उत्पन्न करने की गारंटी नहीं है, है ना? यह देखने के लिए कि वास्तविक अंतर दोनों के बीच क्या है, हम सीधे स्रोत पर जाते हैं और जावा भाषा विशिष्टता, विशेष रूप से 14.14.2, "एन्हांस्ड फॉर स्टेटमेंट" की जाँच करें :

बयान के for बढ़ाया प्रपत्र के बयान के for एक मूल के बराबर है:

 for (I #i = Expression.iterator(); #i.hasNext(); ) { VariableModifiers(opt) Type Identifier = #i.next(); Statement } 

दूसरे शब्दों में, यह जेएलएस द्वारा आवश्यक है कि दोनों बराबर हैं सिद्धांत में जो बाइटकोक्स में सीमांत अंतर का मतलब हो सकता है, लेकिन वास्तविकता में लूप के लिए बढ़ाया आवश्यक है:

  • .iterator() विधि को .iterator()
  • का प्रयोग करें .hasNext()
  • .next() माध्यम से स्थानीय चर उपलब्ध .next()

इसलिए, दूसरे शब्दों में, सभी व्यावहारिक उद्देश्यों के लिए बाइटकोक समान, या लगभग समान होंगे। किसी भी कंपाइलर कार्यान्वयन पर विचार करना कठिन है, जिसके परिणामस्वरूप दोनों के बीच कोई महत्वपूर्ण अंतर होगा।

यदि आपको अपने लूप में संग्रह को संशोधित करने की आवश्यकता है, तो आपको इटेटर का उपयोग करना पड़ सकता है पहला दृष्टिकोण अपवाद फेंक देगा।

 for (String i : list) { System.out.println(i); list.remove(i); // throws exception } Iterator it=list.iterator(); while (it.hasNext()){ System.out.println(it.next()); it.remove(); // valid here } 

इटरेटर जावा कलेक्शंस ढांचे में एक इंटरफ़ेस है जो एक संग्रह से गुज़रने या पुनरावृत्त करने के तरीकों को प्रदान करता है।

दोनों इटरेटर और लूप के लिए इसी तरह कार्य करता है, जब आपका मकसद केवल एक संग्रह पर अपने तत्वों को पढ़ने के लिए पार करना है।

for-each लिए संग्रह पर पुनरावृत्त करने का एकमात्र तरीका है।

उदाहरण के लिए:

 List<String> messages= new ArrayList<>(); //using for-each loop for(String msg: messages){ System.out.println(msg); } //using iterator Iterator<String> it = messages.iterator(); while(it.hasNext()){ String msg = it.next(); System.out.println(msg); } 

और प्रत्येक लूप को केवल इटरेटर इंटरफ़ेस को लागू करने वाले ऑब्जेक्ट पर ही इस्तेमाल किया जा सकता है।

अब लूप और इटरेटर के मामले में वापस।

अंतर तब होता है जब आप किसी संग्रह को संशोधित करने का प्रयास करते हैं। इस मामले में, फर्जी फास्ट प्रॉपर्टी की वजह से इटरेटर अधिक कुशल है । अर्थात। यह अगले तत्व पर जाने से पहले अंतर्निहित संग्रह की संरचना में किसी भी संशोधन की जांच करता है यदि कोई भी संशोधन मिलते हैं, तो यह समवर्ती सुधार को अपनाना होगा

(ध्यान दें: इटेटर का यह कार्यविधि केवल जवा.उटल पैकेज में संग्रह वर्गों के मामले में लागू होता है। यह समवर्ती संकलन के लिए लागू नहीं होता है क्योंकि वे प्रकृति से असफल-सुरक्षित हैं)

foreach हुड के तहत वैसे भी उपयोग करता है I यह वास्तव में वाक्यात्मक चीनी है

निम्न प्रोग्राम पर विचार करें:

 import java.util.List; import java.util.ArrayList; public class Whatever { private final List<Integer> list = new ArrayList<>(); public void main() { for(Integer i : list) { } } } 

चलो इसे javac Whatever.java साथ संकलित करते हैं। javac Whatever.java ,
और javap -c Whatever का उपयोग करते हुए main() javap -c Whatever :

 public void main(); Code: 0: aload_0 1: getfield #4 // Field list:Ljava/util/List; 4: invokeinterface #5, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 9: astore_1 10: aload_1 11: invokeinterface #6, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z 16: ifeq 32 19: aload_1 20: invokeinterface #7, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 25: checkcast #8 // class java/lang/Integer 28: astore_2 29: goto 10 32: return 

हम देख सकते हैं कि foreach एक प्रोग्राम को नीचे संकलित करता है:

  • List.iterator() का उपयोग करते हुए List.iterator() बनाता है List.iterator()
  • यदि Iterator.hasNext() : Iterator.hasNext() आमंत्रित करता है और लूप जारी रहता है

के रूप में "क्यों नहीं इस बेकार लूप संकलित कोड से बाहर अनुकूलित कर रहे हैं? हम देख सकते हैं कि यह सूची आइटम के साथ कुछ भी नहीं करता है": ठीक है, यह संभव है कि आप कोड को अपने .iterator() जैसे कि। साइड इफेक्ट्स हैं, या ऐसा है कि .hasNext() का साइड-इफेक्ट्स या अर्थपूर्ण परिणाम हैं।

आप आसानी से कल्पना कर सकते हैं कि डेटाबेस से स्क्रॉल करने योग्य क्वेरी का एक .hasNext() नाटक करने पर कुछ नाटकीय काम हो सकता है। .hasNext() (डेटाबेस से संपर्क करना या कर्सर को बंद करना क्योंकि आप परिणाम सेट के अंत तक पहुंच गए हैं)।

इसलिए, भले ही हम यह साबित कर सकते हैं कि लूप बॉडी में कुछ भी नहीं होता … यह साबित करने के लिए अधिक महंगा है कि क्या हम सार्थक / परिणामी होते हैं जब हम पुनरावृत्त करते हैं संकलक को प्रोग्राम में यह खाली लूप बॉडी छोड़ना होगा।

सबसे अच्छा हम उम्मीद कर सकते हैं एक संकलक चेतावनी होगी । यह दिलचस्प है कि javac -Xlint:all Whatever.java भी javac -Xlint:all Whatever.java हमें इस खाली लूप बॉडी के बारे में चेतावनी नहीं देती है। IntelliJ आईडीईए हालांकि करता है। बेशक मैंने ईक्लेप्से कंपाइलर का उपयोग करने के लिए IntelliJ को कॉन्फ़िगर किया है, लेकिन ऐसा इसलिए नहीं हो सकता है कि क्यों

यहां छवि विवरण दर्ज करें

संग्रह के साथ काम करते समय हमें पारंपरिक लूप का उपयोग करने से बचना चाहिए। सरल कारण है कि मैं क्या दे दूँगा कि लूप की जटिलता ऑर्डर ओ (एसकेआर (एन)) और इटरेटर की जटिलता या लूप के लिए बढ़ी है, केवल ओ (एन) है। तो यह एक प्रदर्शन अंतर देता है .. बस कुछ 1000 वस्तुओं की सूची ले लीजिए और दोनों तरीकों से प्रिंट करें। और निष्पादन के लिए समय के अंतर भी प्रिंट करें। आप अंतर देख सकते हैं