拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 将java.util.Properties转换为HashMap

将java.util.Properties转换为HashMap

白鹭 - 2021-11-09 2181 0 2

1.简介

许多开发人员决定将应用程序参数存储在源代码之外。在Java中,这样做的方法之一是使用外部配置文件,并通过java.util.Properties类读取它们。


在本教程中,我们将重点介绍**java.util.Properties转换为HashMap<String, String>各种方法**。我们将使用纯Java,lambda或外部库实现不同的方法来实现我们的目标。通过示例,我们将讨论每种解决方案的利弊。

2. HashMap构造函数

在实现第一个代码之前,让我们检查一下Javadoc中的java.util.Properties 。如我们所见,该实用程序类继承自Hashtable<Object, Object> ,后者也实现了Map接口。而且,Java包装了其Reader和Writer类,以直接在String值上工作。


根据这些信息,我们可以使用类型转换和构造函数调用Properties转换为HashMap<String, String>


假设我们已Properties ,则可以实现:

public static HashMap<String, String> typeCastConvert(Properties prop) {

 Map step1 = prop;

 Map<String, String> step2 = (Map<String, String>) step1; return new HashMap<>(step2);

 }

在这里,我们通过三个简单的步骤来实现我们的转换。


首先,根据继承图,我们需要将Properties转换为原始Map 。此操作将强制执行第一个编译器警告,可以使用@SuppressWarnings(“rawtypes”)批注将其禁用。


之后,我们将原始Map转换为Map<String, String> ,从而引起另一个编译器警告,可以通过使用@SupressWarnings(“unchecked”)忽略该警告。


最后,我们使用copy构造函数HashMap 。这是**Properties的最快方法,但是此解决方案还具有与类型安全有关的很大缺点**:转换前,我们的Properties可能会受到损害和修改。


根据文档, Properties类具有setProperty()和getProperty()方法,这些方法强制使用String值。但是还有Hashtable继承的put()和putAll() Properties中将任何类型用作键或值:

properties.put("property4", 456);

 properties.put(5, 10.11);



 HashMap<String, String> hMap = typeCastConvert(properties);

 assertThrows(ClassCastException.class, () -> {

 String s = hMap.get("property4");

 });

 assertEquals(Integer.class, ((Object) hMap.get("property4")).getClass());



 assertThrows(ClassCastException.class, () -> {

 String s = hMap.get(5);

 });

 assertEquals(Double.class, ((Object) hMap.get(5)).getClass());

如我们所见,我们的转换执行没有任何错误,但是HashMap中的.因此,即使此方法看起来最简单,我们将来也必须牢记一些与安全相关的检查。

3. Guava API

如果我们可以使用第三方库,则可以使用Google Guava API。该库提供了一个静态[Maps.fromProperties()](https://guava.dev/releases/snapshot-jre/api/docs/com/google/common/collect/Maps.html#fromProperties-java.util.Properties-)方法,该方法几乎可以为我们做所有事情。根据文档,此调用返回一个ImmutableMap ,因此,如果我们要HashMap,则可以使用:

public HashMap<String, String> guavaConvert(Properties prop) { return Maps.newHashMap(Maps.fromProperties(prop));

 }

如前所述,当我们完全确定Properties仅包含String值**时,此方法可以正常工作。 **某些不合格的值将导致意外的行为:

properties.put("property4", 456);

 assertThrows(NullPointerException.class,

 () -> PropertiesToHashMapConverter.guavaConvert(properties));



 properties.put(5, 10.11);

 assertThrows(ClassCastException.class,

 () -> PropertiesToHashMapConverter.guavaConvert(properties));

Guava API不会执行任何其他映射。结果,它不允许我们转换那些Properties引发异常。


在第一种情况下, Integer值而引发NullPointerException ,无法通过Properties. getProperty()方法,因此被解释为null 。第二个示例抛出与输入属性映射上发生的非字符串ClassCastException


此解决方案为我们提供了更好的类型控制,并且还向我们通知**了转换过程中发生的违规情况。 **

4.自定义类型安全实施

现在是时候根据前面的示例解决类型安全问题了。众所周知, Properties类实现了从Map接口继承的方法。我们将使用一种迭代Map的可能方式来实现适当的解决方案,并通过类型检查来丰富它。

4.1。 for循环迭代

让我们实现一个简单的for -loop:

public HashMap<String, String> loopConvert(Properties prop) {

 HashMap<String, String> retMap = new HashMap<>(); for (Map.Entry<Object, Object> entry : prop.entrySet()) {

 retMap.put(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()));

 } return retMap;

 }

在此方法中,我们以与对典型Map Properties 。 Map.Entry类表示的每个单个键对值进行一对一访问。


在将值放入返回的HashMap ,我们可以执行其他检查,因此我们决定使用String.valueOf()方法。

4.2。 StreamCollectors API

我们甚至可以使用现代Java 8方式重构我们的方法:

public HashMap<String, String> streamConvert(Properties prop) { return prop.entrySet().stream().collect(

 Collectors.toMap(

 e -> String.valueOf(e.getKey()),

 e -> String.valueOf(e.getValue()),

 prev, next) -> next, HashMap::new

 ));

 }

在这种情况下,我们使用的Java 8 Stream Collector没有显式的HashMap构造。此方法实现与上一个示例完全相同的逻辑。


两种解决方案都稍微复杂些,因为它们需要一些自定义实现,而typecasting和Guava示例则不需要。


但是,我们可以在将值放在生成的HashMap上之前访问它们,因此我们可以实现其他检查或映射:

properties.put("property4", 456);

 properties.put(5, 10.11);



 HashMap<String, String> hMap1 = loopConvert(properties);

 HashMap<String, String> hMap2 = streamConvert(properties);



 assertDoesNotThrow(() -> {

 String s1 = hMap1.get("property4");

 String s2 = hMap2.get("property4");

 });

 assertEquals("456", hMap1.get("property4"));

 assertEquals("456", hMap2.get("property4"));



 assertDoesNotThrow(() -> {

 String s1 = hMap1.get("property4");

 String s2 = hMap2.get("property4");

 });

 assertEquals("10.11", hMap1.get("5"));

 assertEquals("10.11", hMap2.get("5"));



 assertEquals(hMap2, hMap1);

如我们所见,我们解决了与非字符串值有关的问题。使用这种方法,我们可以手动调整映射逻辑以实现适当的实现。

5.结论

在本教程中,我们检查了将java.util.Properties转换为HashMap<String, String>不同方法。


我们从类型转换解决方案开始,这也许是最快的转换,但也带来了编译器警告和潜在的类型安全错误。


然后,我们看了一个使用Guava API的解决方案,该解决方案解决了编译器警告并为处理错误提供了一些改进。


最后,我们实现了自定义方法,该方法处理类型安全性错误并提供最大的控制权。


0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *