Java.util को धर्मान्तरित कर रहा है। HashMap <स्ट्रिंग, स्ट्रिंग> के लिए


89
Properties properties = new Properties();
Map<String, String> map = new HashMap<String, String>(properties);// why wrong?

java.util.Propertiesका कार्यान्वयन है java.util.Map, और java.util.HashMapनिर्माता को एक Mapप्रकार का परम प्राप्त होता है । तो, इसे स्पष्ट रूप से क्यों परिवर्तित किया जाना चाहिए?

जवाबों:


86

इसका कारण यह है कि Propertiesविस्तारHashtable<Object, Object> (जो, बदले में, लागू होता है Map<Object, Object>)। आप इसे एक में खिलाने का प्रयास करते हैं Map<String, String>। इसलिए यह असंगत है।

आपको अपने नक्शे में एक-एक करके स्ट्रिंग गुण खिलाने की आवश्यकता है ...

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

for (final String name: properties.stringPropertyNames())
    map.put(name, properties.getProperty(name));

1
हाँ, लेकिन यह यहाँ समस्या नहीं है: सामान्य तर्क मेल नहीं खाते। आप जो कुछ भी चाहते हैं उसे खिला सकते हैं Hashtable<Object, Object>, यहां तक ​​कि ऐसी चीजें जो स्ट्रिंग्स नहीं हैं - यहां तक ​​कि चाबियाँ जो स्ट्रिंग्स नहीं हैं।
fge

@assylias: नहीं, यह भी संकलित नहीं होगा।
जॉन स्कीट

12
1,8 में आप कर सकते हैं गुण ।forEach ((k, v) -> map.put ((स्ट्रिंग) k, (स्ट्रिंग) v));
मोदिफायर

1
या यदि आपके पास हाथ पहले से मौजूद नहीं है, तो प्रॉपर्टीज को हाथ में रखें ।entrySet ()। स्ट्रीम ()। कलेक्टर्स .toMap (e -> (स्ट्रिंग) e.getKey (), e -> (स्ट्रिंग) e.getVideue )))
टॉन्सिक

46

इस तरह से करने के लिए कुशल तरीका है कि एक जेनेरिक मानचित्र पर निम्नानुसार डाला जाए:

Properties props = new Properties();

Map<String, String> map = (Map)props;

यह Map<Object, Object>एक कच्चे मानचित्र में बदल जाएगा , जो संकलक (केवल चेतावनी) के लिए "ठीक" है। एक बार जब हम एक कच्चा है Mapतो यह डाली जाएगी Map<String, String>यह भी "ठीक है" (एक और चेतावनी) होगा। आप एनोटेशन के साथ उन्हें अनदेखा कर सकते हैं@SuppressWarnings({ "unchecked", "rawtypes" })

यह काम करेगा क्योंकि JVM में वस्तु वास्तव में एक सामान्य प्रकार नहीं है। सामान्य प्रकार केवल एक चाल है जो संकलन के समय चीजों को सत्यापित करता है।

यदि कुछ कुंजी या मान स्ट्रिंग नहीं है, तो यह ClassCastExceptionत्रुटि उत्पन्न करेगा । वर्तमान Propertiesकार्यान्वयन के साथ ऐसा होने की संभावना नहीं है, जब तक कि आप सुपर से उत्परिवर्तनीय कॉल विधियों का उपयोग नहीं करते Hashtable<Object,Object>हैं Properties

तो, अगर आपके गुण उदाहरण के साथ बुरा काम नहीं करते हैं यह जाने का रास्ता है।


प्रश्न हैशपाश में बदलना है। कोई नक्शा नहीं।
एलिकएल्ज़िन-किलाका

3
हां, प्रश्न शीर्षक यह कहता है कि, लेकिन लक्ष्य को Mapदिए गए कोड में कम से कम एक उदाहरण है, इसलिए मैंने सोचा कि यह वही है
जिसकी

यद्यपि मुझे अन्य प्यूरिस्ट समाधान पसंद हैं, यह समाधान मेरे लिए आसान है क्योंकि यह केवल एक सरल रेखा है।
अल्फांसो निशिकोवा


27

इस बारे में कैसा है?

   Map properties = new Properties();
   Map<String, String> map = new HashMap<String, String>(properties);

एक चेतावनी का कारण होगा, लेकिन पुनरावृत्तियों के बिना काम करता है।


4
@fge: यह एक नहीं है Map<Object, Object>, यह एक Mapतर्क (कच्चा प्रकार) है। यह उत्तर सही है
लुकास एडर

2
हुह, हां मैंने ग्रहण के साथ प्रयास किया। ग्रहण और जेवैक के बीच उन सामान्य अंतरों में से एक है? .... नहीं, जेवैक के साथ भी काम करता है
लुकास ईडर

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

जैसा कि पिछले उत्तर में कहा गया है, गुण वस्तु पर एक नया उदाहरण बनाने और पुनरावृति करने की आवश्यकता नहीं है। बस एक क्रम का उपयोग करें: (Map<String, String>) ((Map) properties)
रिकार्डो वेलोसो

22

जावा 8 रास्ता:

properties.entrySet().stream().collect(
    Collectors.toMap(
         e -> e.getKey().toString(),
         e -> e.getValue().toString()
    )
);

क्या लंबोदर के बजाय विधि संदर्भ का उपयोग करने का एक तरीका है। सोनार कोबे के मुद्दों को लेकर।
वियान झिंगडे १२'१

16

Propertiesलागू Map<Object, Object>- नहीं Map<String, String>

आप इस निर्माता को कॉल करने का प्रयास कर रहे हैं:

public HashMap(Map<? extends K,? extends V> m)

... के साथ Kऔर Vदोनों के रूप में String

लेकिन Map<Object, Object>यह नहीं है Map<? extends String, ? extends String>... इसमें गैर-स्ट्रिंग कुंजी और मान हो सकते हैं।

यह काम करेगा:

Map<Object, Object> map = new HashMap<Object, Object>();

... लेकिन यह आपके लिए उतना उपयोगी नहीं होगा।

मूल रूप से, Propertiesकभी भी उपवर्ग नहीं बनाया जाना चाहिए HashTable... यही समस्या है। V1 के बाद से, यह हमेशा गैर-स्ट्रिंग कुंजी और मूल्यों को संग्रहीत करने में सक्षम रहा है, इसके बावजूद कि इरादा के खिलाफ है। यदि इसके बजाय संरचना का उपयोग किया गया था, तो एपीआई केवल स्ट्रिंग कुंजी / मूल्यों के साथ काम कर सकता था , और सभी अच्छी तरह से होंगे।

आप कुछ इस तरह चाहते हैं:

Map<String, String> map = new HashMap<String, String>();
for (String key : properties.stringPropertyNames()) {
    map.put(key, properties.getProperty(key));
}

स्पष्ट रूप से यह स्पष्ट रूप से करना संभव नहीं है Properties<String,String> properties = new Properties<String,String>();। अजीब।
eis

1
@eis यह डिजाइन द्वारा, Propertiesस्वयं सामान्य नहीं है।
मैटियस बुलेनेंस

मैं यह कहूंगा कि यह डिजाइन के बजाय विकल्पों की दुर्भाग्यपूर्ण श्रृंखला से है, लेकिन हाँ।
eis

2
@ आईस: नहीं, यह डिजाइन द्वारा है कि गुण एक स्ट्रिंग-टू-स्ट्रिंग मानचित्र होने का मतलब है। यह समझ में आता है कि यह सामान्य नहीं है। इसका कोई मतलब नहीं है कि आप गैर-स्ट्रिंग कुंजी / मान जोड़ सकते हैं।
जॉन स्कीट


8

यदि आप जानते हैं कि आपकी Propertiesवस्तु में केवल <String, String>प्रविष्टियाँ हैं, तो आप कच्चे प्रकार का सहारा ले सकते हैं:

Properties properties = new Properties();
Map<String, String> map = new HashMap<String, String>((Map) properties);

4

समस्या यह है कि है Propertiesलागू करता Map<Object, Object>है, जबकि HashMapनिर्माता एक उम्मीद Map<? extends String, ? extends String>

यह उत्तर इस (काफी प्रति-सहज) निर्णय की व्याख्या करता है। संक्षेप में: जावा 5 से पहले, Propertiesकार्यान्वित किया गया Map(क्योंकि तब कोई जेनरिक वापस नहीं थे)। इसका मतलब यह था कि आप किसी भी वस्तु Objectमें डाल सकते हैं Propertiesयह अभी भी डोकलाम में है:

क्योंकि Propertiesइनहेरिट करने से Hashtable, putऔर putAllतरीकों को एक Propertiesवस्तु पर लागू किया जा सकता है । उनका उपयोग दृढ़ता से हतोत्साहित किया जाता है क्योंकि वे कॉलर को प्रविष्टियाँ डालने की अनुमति देते हैं जिनकी कुंजी या मान Strings नहीं हैं । इसके setPropertyबजाय विधि का उपयोग किया जाना चाहिए।

इस के साथ संगतता बनाए रखने के लिए, डिजाइनरों के पास Map<Object, Object>जावा 5 में इनहेरिट करने के अलावा और कोई विकल्प नहीं था । यह पूर्ण बैकवर्ड संगतता के लिए प्रयास का एक दुर्भाग्यपूर्ण परिणाम है जो नए कोड को अनावश्यक रूप से जटिल बनाता है।

यदि आप कभी भी अपनी संपत्ति में स्ट्रिंग गुणों का उपयोग करते हैं Properties, तो आपको अपने निर्माता में अनियंत्रित डाली से दूर होने में सक्षम होना चाहिए :

Map<String, String> map = new HashMap<String, String>( (Map<String, String>) properties);

या किसी भी प्रतियां के बिना:

Map<String, String> map = (Map<String, String>) properties;

यह HashMap निर्माता का हस्ताक्षर है public HashMap(Map<? extends K, ? extends V> m)। यह उम्मीद नहीं करता हैMap<String, String>
मुबीन

@ मुबीन ठीक है, मैंने मामले को थोड़ा बढ़ा दिया। फिर भी, तर्क रखता है: Map<Object, Object>टाइप 'मैप <के औपचारिक तर्क के लिए इस्तेमाल नहीं किया जा सकता है? स्ट्रिंग बढ़ाता है,? स्ट्रिंग> का विस्तार करता है।
मटियास बुएलेंस

2

यह केवल इसलिए है क्योंकि HashMap के निर्माता को मैप जेनेरिक प्रकार और गुण कार्यान्वयन मानचित्र के लिए एक arg की आवश्यकता होती है।

यह एक चेतावनी के साथ काम करेगा

    Properties properties = new Properties();
    Map<String, String> map = new HashMap(properties);

1

आप इसका उपयोग कर सकते हैं:

Map<String, String> map = new HashMap<>();

props.forEach((key, value) -> map.put(key.toString(), value.toString()));

0

पहली बात,

गुण वर्ग हैशटेबल पर आधारित होता है न कि हैशमैप पर। गुण वर्ग मूल रूप से हैशटेबल का विस्तार करता है

हैशपॉप क्लास में ऐसा कोई कंस्ट्रक्टर नहीं है जो प्रॉपर्टी ऑब्जेक्ट लेता है और आपको हैशमैप ऑब्जेक्ट लौटाता है। तो आप जो कर रहे हैं वह सही नहीं है। आपको हैशटेबल संदर्भ के लिए गुणों की वस्तु कास्ट करने में सक्षम होना चाहिए।


0

मैं इसका उपयोग करता हूं:

for (Map.Entry<Object, Object> entry:properties.entrySet()) {
    map.put((String) entry.getKey(), (String) entry.getValue());
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.