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)

...와 K와 V모두 같은 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상기 put및 putAll방법이 적용될 수있는 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.