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。 Stream
和Collectors
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 评论