Chuyển đổi java.util.Properties thành HashMap <String, String>


Câu trả lời:


86

Điều này là do Propertieskéo dàiHashtable<Object, Object> (đến lượt nó, thực hiện Map<Object, Object>). Bạn cố gắng đưa nó vào một Map<String, String>. Do đó nó không tương thích.

Bạn cần cung cấp từng thuộc tính chuỗi vào bản đồ của mình ...

Ví dụ:

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

1
Có, nhưng đó không phải là vấn đề ở đây: các đối số chung chung không khớp. Bạn có thể cung cấp bất cứ thứ gì bạn muốn trong một Hashtable<Object, Object>, ngay cả những thứ không phải là chuỗi - ngay cả những khóa không phải là chuỗi.
fge

@assylias: Không, điều đó cũng sẽ không biên dịch.
Jon Skeet

13
trong 1,8 bạn có thể làm thuộc tính.forEach ((k, v) -> map.put ((Chuỗi) k, (Chuỗi) v));
ModdyFire 19/02/17

1
Hoặc nếu bạn chưa có bản đồ trong tay property.entrySet (). Stream (). Collect (Collectors.toMap (e -> (String) e.getKey (), e -> (String) e.getValue ( )))
Tonsic

46

Cách hiệu quả để làm điều đó là chỉ truyền đến một Bản đồ chung như sau:

Properties props = new Properties();

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

Điều này sẽ chuyển đổi a Map<Object, Object>thành Bản đồ thô, là "ok" đối với trình biên dịch (chỉ cảnh báo). Sau khi chúng ta có một bản raw, Mapnó sẽ truyền tới Map<String, String>đó nó cũng sẽ là "ok" (một cảnh báo khác). Bạn có thể bỏ qua chúng bằng chú thích@SuppressWarnings({ "unchecked", "rawtypes" })

Điều này sẽ hoạt động vì trong JVM đối tượng không thực sự có một kiểu chung. Loại chung chỉ là một thủ thuật xác minh mọi thứ tại thời điểm biên dịch.

Nếu một số khóa hoặc giá trị không phải là Chuỗi, nó sẽ tạo ra ClassCastExceptionlỗi. Với Propertiesviệc triển khai hiện tại, điều này rất khó xảy ra, miễn là bạn không sử dụng các phương thức gọi có thể thay đổi từ siêu Hashtable<Object,Object>của Properties.

Vì vậy, nếu không làm những điều khó chịu với phiên bản Thuộc tính của bạn thì đây là cách để thực hiện.


Câu hỏi đặt ra là chuyển đổi sang HashMap. Không phải bất kỳ Bản đồ nào.
AlikElzin-kilaka

3
Vâng, tiêu đề câu hỏi nói rằng, nhưng mục đích là để có một Mapví dụ ít nhất là ở các mã nhất định, vì vậy tôi nghĩ rằng đây là những gì anh ta cần
padilo

Mặc dù tôi thích các giải pháp theo chủ nghĩa thuần túy khác, nhưng giải pháp này có ích cho tôi vì nó chỉ là một dòng đơn giản.
Alfonso Nishikawa


27

Còn cái này thì sao?

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

Sẽ gây ra cảnh báo, nhưng hoạt động mà không cần lặp lại.


4
@fge: Không phải a Map<Object, Object>, đó là Mapđối số (kiểu thô). Câu trả lời này là đúng
Lukas Eder

2
Phải, tôi đã thử với Eclipse. Một trong những khác biệt chung giữa Eclipse và javac một lần nữa? .... nope, cũng làm việc với javac
Lukas Eder.

4
Điều này hoạt động nhưng sự lặp lại vẫn xảy ra. Nếu bạn nhìn vào mã nguồn cho HashMap, về cơ bản hàm tạo sẽ lặp lại thông qua tham số bản đồ chung. Vì vậy, thời gian tính toán không thay đổi nhưng mã chắc chắn ngắn gọn hơn.
Simeon G

Như câu trả lời trước đã nêu, không cần tạo một thể hiện mới và lặp lại đối tượng thuộc tính. Chỉ cần sử dụng một chuỗi các diễn viên: (Map<String, String>) ((Map) properties)
Ricardo Veloso

22

Cách Java 8:

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

Có cách nào để sử dụng tham chiếu phương thức thay vì lambda. Cos của các vấn đề qube sonar.
Viyaan Jhiingade

16

Propertiesnông cụ Map<Object, Object>- không phải Map<String, String>.

Bạn đang cố gọi hàm tạo này:

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

... với KVcả hai như String.

Nhưng Map<Object, Object>không phải là Map<? extends String, ? extends String>... nó có thể chứa các khóa và giá trị không phải chuỗi.

Điều này sẽ hoạt động:

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

... nhưng nó sẽ không hữu ích cho bạn.

Về cơ bản, Propertieskhông bao giờ nên được tạo thành một lớp con của HashTable... đó là vấn đề. Kể từ phiên bản v1, nó luôn có thể lưu trữ các khóa và giá trị không phải Chuỗi, mặc dù điều đó là trái với ý định. Nếu thành phần đã được sử dụng thay thế, API có thể chỉ hoạt động với các khóa / giá trị chuỗi và tất cả sẽ tốt.

Bạn có thể muốn một cái gì đó như thế này:

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

rõ ràng nó cũng không thể làm một cách rõ ràng Properties<String,String> properties = new Properties<String,String>();. Kỳ lạ.
eis

1
@eis Đó là do thiết kế, Propertiesbản thân nó không phải là chung chung.
Mattias Buelens

Tôi muốn nói rằng đó là bởi một loạt các lựa chọn đáng tiếc hơn là bởi thiết kế, nhưng đúng vậy.
eis

2
@eis: Không, theo thiết kế thì Thuộc tính có nghĩa là một bản đồ chuỗi thành chuỗi. Có nghĩa là nó không chung chung. Sẽ không hợp lý khi bạn có thể thêm các khóa / giá trị không phải chuỗi.
Jon Skeet


8

Nếu bạn biết rằng Propertiesđối tượng của mình chỉ chứa <String, String>các mục nhập, bạn có thể sử dụng kiểu thô:

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

4

Vấn đề là nó Propertiesthực hiện Map<Object, Object>, trong khi hàm HashMaptạo mong đợi a Map<? extends String, ? extends String>.

Câu trả lời này giải thích quyết định (khá phản trực giác) này. Tóm lại: trước Java 5, đã được Propertiesthực hiện Map(vì khi đó chưa có số liệu chung). Điều này có nghĩa là bạn có thể đặt bất kỳ thứ gì Object vào một Propertiesđối tượng. Điều này vẫn còn trong tài liệu:

Bởi vì Propertieskế thừa từ Hashtable, các phương thức putputAllcó thể được áp dụng cho một Propertiesđối tượng. Việc sử dụng chúng không được khuyến khích vì chúng cho phép người gọi chèn các mục nhập có khóa hoặc giá trị không phải Stringlà s. Các setPropertyphương pháp nên được sử dụng để thay thế.

Để duy trì khả năng tương thích với điều này, các nhà thiết kế không có lựa chọn nào khác ngoài việc làm cho nó kế thừa Map<Object, Object>trong Java 5. Đó là một kết quả đáng tiếc của nỗ lực tương thích ngược hoàn toàn khiến mã mới trở nên phức tạp một cách không cần thiết.

Nếu bạn chỉ sử dụng thuộc tính chuỗi trong Propertiesđối tượng của mình , bạn sẽ có thể thoát khỏi kiểu ép kiểu không được kiểm tra trong hàm tạo của mình:

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

hoặc không có bất kỳ bản sao nào:

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

Đây là chữ ký của hàm tạo HashMap public HashMap(Map<? extends K, ? extends V> m). Nó không hy vọng mộtMap<String, String>
Mubin

@Mubin Được rồi, tôi đơn giản hóa vấn đề một chút. Tuy nhiên, đối số vẫn giữ nguyên: a Map<Object, Object>không thể được sử dụng cho đối số chính thức của kiểu `Bản đồ <? mở rộng chuỗi,? mở rộng Chuỗi> `.
Mattias Buelens

2

điều này chỉ là do phương thức khởi tạo của HashMap yêu cầu một đối số của kiểu chung của Bản đồ và Thuộc tính thực hiện Bản đồ.

Điều này sẽ hoạt động, mặc dù với một cảnh báo

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

1

Bạn có thể sử dụng cái này:

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

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

0

Điều đầu tiên,

Lớp thuộc tính dựa trên Hashtable chứ không phải Hashmap. Lớp thuộc tính về cơ bản mở rộng Hashtable

Không có hàm tạo nào như vậy trong lớp HashMap lấy một đối tượng thuộc tính và trả về cho bạn một đối tượng bản đồ băm. Vì vậy, những gì bạn đang làm là KHÔNG đúng. Bạn sẽ có thể truyền đối tượng thuộc tính thành tham chiếu bảng băm.


0

tôi sử dụng cái này:

for (Map.Entry<Object, Object> entry:properties.entrySet()) {
    map.put((String) entry.getKey(), (String) entry.getValue());
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.