2010-07-15 14 views
25

बंद करना मैंने close() विधि का उपयोग कर अंत में जारी किए जाने वाले संसाधन का उपयोग कर एक कस्टम java.util.Iterator लागू किया है। यही कारण है कि संसाधन हो सकता है एक java.sql.ResultSet, एक java.io.InputStream आदि ...java.util.Iterator

public interface CloseableIterator<T> extends Iterator<T> 
    { 
    public void close(); 
    } 

इस इटरेटर का उपयोग कर पता नहीं हो सकता है कि यह बंद होना चाहिए कुछ बाहरी पुस्तकालयों। उदाहरण:

public boolean isEmpty(Iterable<T> myiterable) 
{ 
return myiterable.iterator().hasNext(); 
} 

उस मामले में, इस इटरेटर को बंद करने का कोई तरीका है?

अद्यतन: वर्तमान उत्तरों के लिए बहुत धन्यवाद। मैं सभी को एक (+1) दूंगा। हैनक्स्ट() झूठी रिटर्न देता है जब मैं पहले से ही इटरेटर बंद कर देता हूं। मेरी समस्या तब होती है जब लूप इटेटिंग से पहले अंतिम उदाहरण के रूप में दिखाया गया है जैसा कि यह मेरे उदाहरण में दिखाया गया है।

उत्तर

8

समस्या पर स्थिति है। अक्सर हम एक पूर्ण संग्रह या डेटा सेट पर फिर से शुरू होते हैं, इसलिए हम इस समय पर हैं, पढ़ने के लिए कोई डेटा शेष नहीं है।

लेकिन अगर हम डेटा के अंत तक पहुंचने से पहले लूप से ब्रेक आउट करते हैं, तो इटेटरेटर खत्म नहीं होगा और बंद नहीं होगा।

निर्माण के दौरान इटरेटर में डेटा स्रोत की सामग्री को कैश करने और संसाधन को बंद करने का एक तरीका हो सकता है। तो इटेटरेटर खुले संसाधन पर काम नहीं करेगा लेकिन कैश डेटा पर काम करेगा।

+1

पक्का काम करता है, लेकिन बहुत स्मृति कुशल नहीं हो सकता है, या कैशिंग एक बहुत भारी आपरेशन बन सकता है। – Eric

8

आप इसे finalizer पर बंद कर सकते हैं लेकिन यह आपको वह व्यवहार देने वाला नहीं है जिसे आप चाहते हैं। आपका फाइनलाइज़र केवल तभी बुलाया जाता है जब कचरा कलेक्टर आपकी ऑब्जेक्ट को साफ़ करना चाहता है, इसलिए आपका संसाधन खुला रहता है। इससे भी बदतर, अगर कोई आपके इटरेटर पर रहता है, तो यह कभी बंद नहीं होगा।

हैक्स्ट() के पहले कॉल पर स्ट्रीम को बंद करने की संभावना है जो झूठी रिटर्न देता है। यह अभी भी ऐसा करने की गारंटी नहीं है क्योंकि कोई व्यक्ति केवल पहले तत्व को पुन: सक्रिय कर सकता है और कभी इसके साथ परेशान नहीं होता है।

वास्तव में, मुझे लगता है कि बाहरी पुस्तकालय से निपटने के दौरान आपको इसे स्वयं प्रबंधित करना होगा। आप उन कॉल को उन तरीकों से बनाने जा रहे हैं जो पुनरावर्तनीय उपयोग करते हैं, तो जब आप पूरा कर लें तो इसे बंद न करें? संसाधन प्रबंधन ऐसा कुछ नहीं है जिसे आप बाहरी पुस्तकालय पर लगा सकते हैं जो किसी भी बेहतर तरीके से नहीं जानता है।

12

आपके कार्यान्वयन में यदि आप थियेटरेटर समाप्त हो जाते हैं तो आप इसे स्वयं बंद कर सकते हैं।

public boolean hasNext() { 
     .... 
     if(!hasNext) { 
      this.close(); 
     } 
     return hasNext; 
} 

और स्पष्ट रूप से दस्तावेज़:

यह इटरेटर लागू करेगा पास() जब hasNext(), झूठी वापसी अगर तुम से पहले सुनिश्चित करें कि आप बंद अपने आप

फोन बनाने इटरेटर निपटान के लिए की जरूरत है

उदाहरण:

void testIt() { 
    Iterator i = DbIterator.connect("db.config.info.here"); 
    try { 
      while(i.hasNext() { 
       process(i.next()); 
      } 
     } finally { 
      if(i != null) { 
       i.close(); 
      } 
     } 
    } 

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

4

बस इटरेटर के अपने स्वयं के इंटरफ़ेस को परिभाषित करें जिसमें एक करीबी विधि शामिल है, और सुनिश्चित करें कि आप नियमित इटरेटर कक्षा के बजाय इसका उपयोग करते हैं। उदाहरण के लिए, इस इंटरफ़ेस बनाने:

import java.io.Closeable; 
import java.util.Iterator; 

public interface CloseableIterator<T> extends Iterator<T>, Closeable {} 

और फिर एक कार्यान्वयन इस प्रकार दिखाई देंगे:

List<String> someList = Arrays.asList("what","ever"); 
final Iterator<String> delegate = someList.iterator(); 
return new CloseableIterator<String>() { 
    public void close() throws IOException { 
     //Do something special here, where you have easy 
     //access to the vars that created the iterator 
    } 

    public boolean hasNext() { 
     return delegate.hasNext(); 
    } 

    public String next() { 
     return delegate.next(); 
    } 

    public void remove() { 
     delegate.remove(); 
    } 
}; 
+0

यह कोई जवाब नहीं है, क्योंकि यह उन मॉड्यूल को बनाने का तरीका नहीं बताता है, जो एक बंद करने योग्य इटरेटर को बंद करने के लिए बंद करने योग्य इटरेटर्स के बारे में कुछ भी नहीं जानते हैं। – ceving

+0

मुझे समझ में नहीं आता कि आप क्या कहने की कोशिश कर रहे हैं। उस बाहरी मॉड्यूल के स्रोत कोड को बदलने के बिना, आपको कुछ नया व्यवहार जोड़ने के लिए कोई बाहरी मॉड्यूल कैसे मिलेगा (जैसे एक इटरेटर बंद करना)? संभवतः, बाहरी मॉड्यूल के पास निकट() समय से कॉल करने का कोई कारण नहीं है। –

+0

जिस दृष्टिकोण को मैंने रेखांकित किया है, उसका उपयोग आपको एक इटरेटर प्रदान करेगा जो मौजूदा मॉड्यूल के साथ उपयोग किया जा सकता है (और नतीजे() को समाप्त होने से पहले बंद नहीं किया जा सकता है), या आपके नियंत्रण में मॉड्यूल के साथ (जो उपयुक्त होने पर बंद() को कॉल करेगा) । यह कैसे सुधार किया जा सकता है? –

9

जो AutoCloseable interface

public interface CloseableIterator<T> extends Iterator<T>, AutoCloseable { 
} 

लागू एक कस्टम इटरेटर बनाएं और फिर इस इटरेटर का उपयोग try with resource statement में।

try(CloseableIterator iterator = dao.findAll()) { 
    while(iterator.hasNext()){ 
     process(iterator.next()); 
    } 
} 

यह पैटर्न अंतर्निहित संसाधन जो कुछ भी होता है बंद हो जाएगा: - बयान पूरा के बाद - और एक अपवाद फेंक दिया जाता है, भले ही

अंत में, स्पष्ट रूप से दस्तावेज़ कैसे इस इटरेटर इस्तेमाल किया जाना चाहिए।

यदि आप करीबी कॉल का प्रतिनिधि नहीं देना चाहते हैं, तो पुश रणनीति का उपयोग करें। जैसे। जावा 8 लैम्ब्डा के साथ:

dao.findAll(r -> process(r)); 
1

मैं एक वस्तु धारा की तरह एक इटरेटर का उपयोग कर अपनी परियोजनाओं में से एक में एक ऐसी ही समस्या हुई। इटरेटर पूरी तरह से उपभोग नहीं होने के समय को कवर करने के लिए, मुझे एक करीबी विधि की भी आवश्यकता होती है। प्रारंभ में मैंने आसानी से इटरेटर और क्लोजेबल इंटरफेस बढ़ाए, लेकिन थोड़ा गहरा खोदना, जावा 1.7 में पेश किए गए संसाधनों के साथ-साथ संसाधनों का बयान खोला, मैंने सोचा कि इसे लागू करने का एक साफ तरीका प्रदान किया गया है।

आप इटरेटर और ऑटोक्लोसेबल इंटरफेस का विस्तार करते हैं, बंद विधि को लागू करते हैं और संसाधनों के साथ प्रयास में इटरेटर का उपयोग करते हैं। Iterator गुंजाइश से बाहर होने के बाद रनटाइम आपके लिए करीबी कॉल करेगा।

https://docs.oracle.com/javase/7/docs/api/java/lang/AutoCloseable.html

https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

उदाहरण के लिए

इंटरफ़ेस: public interface MyIterator<E> extends Iterator<E>, AutoCloseable { }

यह का एक कार्यान्वयन: ` सार्वजनिक वर्ग MyIteratorImpl लागू करता MyIterator {

private E nextItem = null; 

@Override 
public boolean hasNext() { 
    if (null == nextItem) 
     nextItem = getNextItem(); 

    return null != nextItem; 
} 

@Override 
public E next() { 
    E next = hasNext() ? nextItem : null; 
    nextItem = null; 
    return next; 
} 

@Override 
public void close() throws Exception { 
    // Close off all your resources here, Runtime will call this once 
     Iterator out of scope. 
} 

private E getNextItem() { 
    // parse/read the next item from the under laying source. 
    return null; 
} 

} `

और कोशिश -साथ-संसाधन के साथ इसे का उपयोग का एक उदाहरण:

` सार्वजनिक वर्ग MyIteratorConsumer {

/** 
* Simple example of searching the Iterator until a string starting 
* with the given string is found. 
* Once found, the loop stops, leaving the Iterator partially consumed. 
* As 'stringIterator' falls out of scope, the runtime will call the 
* close method on the Iterator. 
* @param search the beginning of a string 
* @return The first string found that begins with the search 
* @throws Exception 
*/ 
public String getTestString(String search) throws Exception { 
    String foundString = null; 

    try (MyIterator<String> stringIterator = new MyIteratorImpl<>()) { 
     while (stringIterator.hasNext()) { 
      String item = stringIterator.next(); 
      if (item.startsWith(search)) { 
       foundString = item; 
       break; 
      } 
     } 

    } 
    return foundString; 
} 

} `

0

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

उदाहरण:

StreamSupport.stream(Spliterators.spliteratorUnknownSize(
     new MyCustomIterator<T>(), 0), false).onClose(() -> { 
    // close logic here 
}); 
संबंधित मुद्दे