Java.util.Properties'i HashMap <String, String> 'e dönüştürme


Yanıtlar:


89

Bunun nedeni PropertiesgenişlemesidirHashtable<Object, Object> (sırayla uygular Map<Object, Object>). Bunu bir Map<String, String>. Bu nedenle uyumsuzdur.

Dize özelliklerini tek tek haritanıza beslemeniz gerekiyor ...

Örneğin:

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

1
Evet, ama buradaki sorun bu değil: genel argümanlar uyuşmuyor. Hashtable<Object, Object>Dizge olmayan şeyler de dahil olmak üzere istediğiniz her şeyi besleyebilirsiniz - dizge olmayan anahtarlar bile .
fge

@assylias: Hayır, bu da derlenmeyecek.
Jon Skeet

13
1,8'de properties.forEach ((k, v) -> map.put ((String) k, (String) v));
ModdyFire

1
Veya properties.entrySet (). Stream (). Collect (Collectors.toMap (e -> (String) e.getKey (), e -> (String) e.getValue ( )))
Tonsic

47

Bunu yapmanın etkili yolu, aşağıdaki gibi genel bir Haritaya atılmaktır:

Properties props = new Properties();

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

Bu, a'yı Map<Object, Object>derleyici için "tamam" olan bir ham Haritaya dönüştürür (yalnızca uyarı). Biz çiğ sahip olduktan Mapo kadar kullanacaklar Map<String, String>o da (başka uyarı) "Tamam" olacak. Ek açıklama ile onları görmezden gelebilirsiniz@SuppressWarnings({ "unchecked", "rawtypes" })

Bu işe yarayacaktır çünkü JVM'de nesnenin gerçekten genel bir türü yoktur. Soysal türler, işleri derleme zamanında doğrulayan bir numaradır.

Bazı anahtar veya değer bir Dize değilse, bir ClassCastExceptionhata oluşturur. Geçerli ile Propertiesuygulanması bu sürece süperden değişken çağrı yöntemlerini kullanmayın olarak, gerçekleşmesi pek olası değildir Hashtable<Object,Object>ait Properties.

Öyleyse, Properties örneğinizle kötü şeyler yapmazsanız, gidilecek yol budur.


Soru, HashMap'e dönüştürmektir. Herhangi bir Harita değil.
AlikElzin-kilaka

3
Evet, soru başlığı bunu söylüyor, ancak amaç Mapen azından verilen kodda bir örneğe sahip olmak , bu yüzden ihtiyacı olan şeyin bu olduğunu düşündüm
padilo

Diğer sadık çözümleri sevmeme rağmen, bu çözüm bana çok kullanışlı geliyor çünkü bu sadece basit bir hat.
Alfonso Nishikawa


28

Buna ne dersin?

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

Bir uyarıya neden olur, ancak yineleme olmadan çalışır.


4
@fge: Bu bir değil Map<Object, Object>, bir Mapargüman (ham tip). Bu cevap doğru
Lukas Eder

2
Huh, evet Eclipse ile denedim. Eclipse ve javac arasındaki bu genel farklardan biri yine mi? .... hayır, javac ile de çalışıyor
Lukas Eder

4
Bu işe yarıyor, ancak yineleme hala devam ediyor. HashMap için kaynak koduna bakarsanız, yapıcı temelde genel eşleme parametresini yineler. Dolayısıyla hesaplama süresi değişmez ancak kod kesinlikle daha kısadır.
Simeon G

Önceki yanıtta belirtildiği gibi, yeni bir örnek oluşturmaya ve özellikler nesnesi üzerinde yineleme yapmaya gerek yoktur. Sadece bir dizi yayın kullanın: (Map<String, String>) ((Map) properties)
Ricardo Veloso

23

Java 8 yolu:

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

Lambda yerine yöntem başvurusunu kullanmanın bir yolu var mı? Sonar qube sorunları nedeniyle.
Viyaan Jhiingade

17

Propertiesuygular Map<Object, Object>- değil Map<String, String>.

Bu kurucuyu aramaya çalışıyorsunuz:

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

... ile Kve Vher ikisi ile String.

Ama Map<Object, Object>bir Map<? extends String, ? extends String>... dize olmayan anahtarlar ve değerler içerebilir.

Bu işe yarar:

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

... ama senin için o kadar yararlı olmayacak.

Temelde, Propertiesasla bir alt sınıf yapılmamalıydı HashTable... sorun bu. V1'den beri, amaca aykırı olmasına rağmen, String olmayan anahtarları ve değerleri her zaman depolayabiliyor. Bunun yerine kompozisyon kullanılmış olsaydı, API yalnızca dize anahtarları / değerleriyle çalışabilirdi ve her şey yolunda olurdu.

Bunun gibi bir şey isteyebilirsiniz:

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

görünüşe göre açıkça yapmak da mümkün değil Properties<String,String> properties = new Properties<String,String>();. Tuhaf.
eis

1
@eis Bu, tasarım gereği Propertiesgenel değildir.
Mattias Buelens

Bunun tasarımdan ziyade talihsiz bir dizi seçim olduğunu söylemeyi tercih ederim, ama evet.
eis

2
@eis: Hayır, Özellikler'in dizeden dizgeye bir eşleşme olması tasarım gereği. Genel olmadığı mantıklı. O değil olmayan dize tuşları / değerleri ekleyebilirsiniz mantıklı.
Jon Skeet


8

Eğer varsa bilmek sizin o Propertiesnesne yalnızca içeren <String, String>girdileri, bir ham türüne çare olabilir:

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

4

Sorun, Propertiesuygulayan Map<Object, Object>, ancak HashMapkurucu bir Map<? extends String, ? extends String>.

Bu cevap , bu (oldukça sezgisel) kararı açıklar. Kısaca: Java 5'ten önce Propertiesuygulandı Map(o zamanlar jenerik olmadığından). Bu, herhangi Object bir Propertiesnesneyi bir nesneye koyabileceğiniz anlamına geliyordu . Bu hala dokümantasyonda:

'Dan Propertiesmiras aldığından Hashtable, putve putAllyöntemleri bir Propertiesnesneye uygulanabilir . Arayanın anahtarları veya değerleri Strings olmayan girişler eklemesine izin verdikleri için bunların kullanımı kesinlikle önerilmez . Bunun setPropertyyerine yöntem kullanılmalıdır.

Bununla uyumluluğu sürdürmek için, tasarımcıların onu Map<Object, Object>Java 5'te miras almaktan başka seçeneği yoktu . Bu, yeni kodu gereksiz yere karıştıran tam bir geriye dönük uyumluluk çabasının talihsiz bir sonucudur.

Yalnızca hiç dize özelliklerini kullanırsanız Propertiesnesne, sen gerektiğini Yapıcınızda denetlenmeyen bir döküm ile kurtulmak mümkün:

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

veya kopyasız:

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

Bu, HashMap yapıcısının imzasıdır public HashMap(Map<? extends K, ? extends V> m). Bu bir bekler gelmezMap<String, String>
Mübin

@Mubin Tamam, konuyu biraz fazla basitleştirdim. Yine de argüman geçerli: a Map<Object, Object>, 'Map <? Türündeki resmi bir argüman için kullanılamaz. String,? String> `genişler.
Mattias Buelens

2

bunun nedeni yalnızca HashMap yapıcısının Map generic türünde bir argüman gerektirmesi ve Properties'in Map uygulamasını kullanmasıdır.

Bu bir uyarı olsa da işe yarayacak

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

1

Bunu kullanabilirsiniz:

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

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

0

İlk şey,

Özellikler sınıfı Hashmap'e değil Hashtable'a dayanır. Özellikler sınıfı temelde Hashtable'ı genişletir

HashMap sınıfında bir properties nesnesini alıp size bir hashmap nesnesi döndüren böyle bir kurucu yoktur. Yani yaptığınız şey doğru DEĞİL. Özellikler nesnesini hashtable referansına çevirebilmelisiniz.


0

Bunu kullanıyorum:

for (Map.Entry<Object, Object> entry:properties.entrySet()) {
    map.put((String) entry.getKey(), (String) entry.getValue());
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.