java.util.Properties를 HashMap <String, String>으로 변환


답변:


86

이는 PropertiesextendsHashtable<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 : 아니요, 그것도 컴파일되지 않습니다.
Jon Skeet

13
1,8에서는 properties.forEach ((k, v)-> map.put ((String) k, (String) v));
ModdyFire

1
또는 아직 손에 맵이없는 경우 properties.entrySet (). stream (). collect (Collectors.toMap (e-> (String) e.getKey (), e-> (String) e.getValue ( )))
Tonsic

46

이를위한 효율적인 방법은 다음과 같이 일반 맵으로 캐스팅하는 것입니다.

Properties props = new Properties();

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

Map<Object, Object>이는를 원시 맵으로 변환하며 컴파일러에 대해 "정상"입니다 (경고 만 해당). 우리가 원시가 있으면 Map그것을 캐스팅됩니다 Map<String, String>그것은 또한 (다른 경고) "OK"가 될 것이다. 주석으로 무시할 수 있습니다.@SuppressWarnings({ "unchecked", "rawtypes" })

이것은 JVM에서 객체가 실제로 제네릭 유형을 갖지 않기 때문에 작동합니다. 제네릭 타입은 컴파일 타임에 확인하는 트릭 일뿐입니다.

일부 키 또는 값이 문자열이 아닌 경우 ClassCastException오류가 발생합니다. 현재 Properties구현에서는 super Hashtable<Object,Object>of Properties.

따라서 Properties 인스턴스로 불쾌한 일을하지 않으면 이것이 갈 길입니다.


문제는 HashMap으로 변환하는 것입니다. 지도가 아닙니다.
AlikElzin-kilaka

3
네, 질문 제목은 말한다, 그러나 목표는 것입니다 Map나는이 그가 무엇을 필요로하는지이라고 생각하므로, 주어진 코드를 적어도 인스턴스를
padilo

나는 다른 순수주의 솔루션을 좋아하지만,이 솔루션은 단지 하나의 단순한 라인이기 때문에 내게 편리합니다.
알폰소 니시카와


27

이건 어때?

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

경고가 발생하지만 반복없이 작동합니다.


4
@fge : 그것은 아니다 Map<Object, Object>, 그것은의 Map인수 (원시 형). 이 답변은 정확
루카스 에더

2
네, Eclipse로 시도했습니다. Eclipse와 javac의 일반적인 차이점 중 하나는 무엇입니까? .... 아니,뿐만 아니라 javac의 작동
루카스 에더

4
이것은 작동하지만 반복은 여전히 ​​발생합니다. HashMap의 소스 코드를 보면 생성자가 기본적으로 일반 맵 매개 변수를 반복합니다. 따라서 계산 시간은 변경되지 않지만 코드는 확실히 더 간결합니다.
Simeon G

이전 답변에서 언급했듯이 새 인스턴스를 만들고 속성 개체를 반복 할 필요가 없습니다. : 그냥 캐스트의 연속 사용 (Map<String, String>) ((Map) properties)
리카르도 벨로

22

자바 8 방식 :

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

람다 대신 메서드 참조를 사용하는 방법이 있습니까? 수중 음파 탐지기 qube 문제의 Cos.
Viyaan Jhiingade

17

Properties구현 Map<Object, Object>하지 않습니다 Map<String, String>.

이 생성자를 호출하려고합니다.

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

...와 KV모두 같은 String.

그러나 Map<Object, Object>그렇지 않습니다 Map<? extends String, ? extends String>... 문자열이 아닌 키와 값을 포함 할 수 있습니다.

이것은 작동합니다.

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

...하지만 그것은 당신에게 유용하지 않을 것입니다.

근본적으로, ... Properties의 하위 클래스로 만들지 말았어야했습니다 HashTable. 그게 문제입니다. v1 이후로 의도에 어긋나더라도 항상 비 문자열 키와 값을 저장할 수있었습니다. 컴포지션이 대신 사용 되었다면 API는 문자열 키 / 값으로 작동 할 수 있으며 모두 잘되었을 것입니다.

다음과 같은 것을 원할 수 있습니다.

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그 자체가 일반적이지 않습니다.
마티아스 Buelens

차라리 디자인보다는 불행한 일련의 선택에 의한 것이라고 말하고 싶지만 네.
eis

2
@eis : 아니요, 속성이 문자열-문자열 맵을 의미하는 것은 의도적으로 설계된 것입니다. 그것이 일반적이지 않다는 것은 의미가 있습니다. 그것은 하지 않습니다 가 아닌 문자열 키 / 값을 추가 할 수 있음을 의미합니다.
Jon Skeet


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>.

이 답변은 (상당히 반 직관적 인) 결정을 설명합니다. 요컨대 : Java 5 이전에 Properties구현되었습니다 Map(당시에는 제네릭이 없었기 때문에). 이것은 당신이 어떤 Object 것을 Properties객체에 넣을 수 있음을 의미 합니다. 이것은 여전히 ​​문서에 있습니다.

때문에 Properties상속에서 Hashtable상기 putputAll방법이 적용될 수있는 Properties개체. 호출자가 키나 값이 Strings 가 아닌 항목을 삽입 할 수 있으므로 사용하지 않는 것이 좋습니다 . setProperty방법 대신에 사용되어야한다.

이것과의 호환성을 유지하기 위해 디자이너는 Map<Object, Object>Java 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>
무빈

@Mubin 좋아, 나는 문제를 약간 지나치게 단순화했다. 여전히 인수는 다음과 같습니다. a Map<Object, Object>는 형식`Map <?의 형식 인수에 사용할 수 없습니다. 확장 문자열,? 확장 String>`.
마티아스 Buelens

2

이것은 HashMap의 생성자가 Map 제네릭 유형의 인수를 필요로하고 Properties가 Map을 구현하기 때문입니다.

경고와 함께 작동하지만

    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

우선

속성 클래스는 Hashmap이 아닌 Hashtable을 기반으로합니다. 속성 클래스는 기본적으로 Hashtable을 확장합니다.

HashMap 클래스에는 속성 객체를 가져와 해시 맵 객체를 반환하는 생성자가 없습니다. 그래서 당신이하는 일은 정확하지 않습니다. 속성 개체를 해시 테이블 참조로 캐스팅 할 수 있어야합니다.


0

나는 이것을 사용한다 :

for (Map.Entry<Object, Object> entry:properties.entrySet()) {
    map.put((String) entry.getKey(), (String) entry.getValue());
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.