एक कस्टम तुलनित्र के साथ ट्रीसेट से हटाने से आइटम का एक बड़ा सेट क्यों नहीं निकलता है?


22

जावा 8 और जावा 11 दोनों का उपयोग करते हुए, TreeSetएक String::compareToIgnoreCaseतुलनित्र के साथ निम्नलिखित पर विचार करें :

final Set<String> languages = new TreeSet<>(String::compareToIgnoreCase);
languages.add("java");
languages.add("c++");
languages.add("python");

System.out.println(languages);                 // [c++, java, python]

जब मैं इसमें मौजूद सटीक तत्वों को हटाने की कोशिश करता हूं TreeSet, तो यह काम करता है: निर्दिष्ट सभी हटा दिए जाते हैं:

languages.removeAll(Arrays.asList("PYTHON", "C++"));

System.out.println(languages);                 // [java]

हालांकि, अगर मैं बजाय दूर करने की कोशिश अधिक से में मौजूद है TreeSet, कॉल कुछ भी सब पर नहीं निकालता है (यह बाद में एक कॉल नहीं है, लेकिन इसके बाद के संस्करण का टुकड़ा के बजाय कहा जाता है):

languages.removeAll(Arrays.asList("PYTHON", "C++", "LISP"));

System.out.println(languages);                 // [c++, java, python]

मैं क्या गलत कर रहा हूं? यह इस तरह से व्यवहार क्यों करता है?

संपादित करें: String::compareToIgnoreCaseएक मान्य तुलनित्र है:

(l, r) -> l.compareToIgnoreCase(r)

5
संबंधित बग प्रविष्टि: bugs.openjdk.java.net/browse/JDK-8180409 (TreeSet String.CASE_INSENSITIVE_ORDER के साथ सभी असंगत व्यवहार)
Progman

एक निकट संबंधी प्रश्नोत्तर
नमन

जवाबों:


22

यहाँ हटाने के javadoc है () :

यह कार्यान्वयन निर्धारित करता है कि प्रत्येक पर आकार विधि को लागू करके इस सेट और निर्दिष्ट संग्रह में से कौन सा छोटा है। यदि इस सेट में कम तत्व हैं, तो कार्यान्वयन इस सेट पर पुनरावृत्त करता है, यह देखने के लिए कि बदले में निर्दिष्ट संग्रह में निहित है, यह देखने के लिए प्रत्येक तत्व को पुनरावृत्त द्वारा लौटाता है। यदि यह बहुत सम्‍मिलित है, तो इसे इट्रेटर की निष्कासन विधि के साथ इस सेट से हटा दिया जाता है। यदि निर्दिष्ट संग्रह में कम तत्व हैं, तो कार्यान्वयन निर्दिष्ट संग्रह पर पुनरावृत्त करता है, इस सेट से हटाकर, इस सेट को हटाने की विधि का उपयोग करके, इट्रेटर द्वारा लौटाए गए प्रत्येक तत्व को हटा देता है।

अपने दूसरे प्रयोग में, आप जावदोक के पहले मामले में हैं। तो यह "जावा", "सी ++", इत्यादि पर पुनरावृत्त करता है और जांचता है कि क्या वे सेट में निहित हैं Set.of("PYTHON", "C++")। वे नहीं हैं, इसलिए उन्हें हटाया नहीं गया है। तर्क के रूप में एक ही तुलनित्र का उपयोग करके एक और ट्रीसेट का उपयोग करें, और यह ठीक काम करना चाहिए। दो अलग-अलग सेट कार्यान्वयनों का उपयोग करना, एक का उपयोग करना equals(), और दूसरे का एक तुलनित्र का उपयोग करना, वास्तव में करना एक खतरनाक बात है।

ध्यान दें कि इस बारे में एक बग खोला गया है: [JDK-8180409] ट्रीसेट को सभी असंगत व्यवहार String.CASE_INSENSITIVE_ORDER के साथ हटा दें


क्या आपका मतलब है जब दोनों सेटों में समान विशेषताएं होंगी, यह काम करता है? final Set<String> subLanguages = new TreeSet<>(String::compareToIgnoreCase); subLanguages.addAll(Arrays.asList("PYTHON", "C++", "LISP")); languages.removeAll(subLanguages);
निकोलस

1
आप मामले में हैं "यदि इस सेट में कम तत्व हैं", जो कि javadoc द्वारा वर्णित है। अन्य मामला "यदि निर्दिष्ट संग्रह में कम तत्व हैं"।
जेबी निजेट

8
यह उत्तर सही है, लेकिन यह बहुत ही अनपेक्षित व्यवहार है। यह डिजाइन में एक दोष की तरह लगता है TreeSet
Boann

मैं सहमत हूं, लेकिन मैं इस बारे में कुछ नहीं कर सकता।
जेबी निज़ात

4
यह दोनों है: यह एक बहुत ही अनपेक्षित व्यवहार है जिसे सही ढंग से प्रलेखित किया गया है, लेकिन, अनजाने और धोखेबाज होने के नाते, यह एक डिज़ाइन बग भी है, जो किसी दिन, निश्चित हो सकता है।
जेबी निजेट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.