【问题标题】:Restrict HashMap to accept a particular string key限制 HashMap 接受特定的字符串键
【发布时间】:2014-12-10 15:47:47
【问题描述】:

我们如何限制 HashMap 接受特定的字符串键。
这里的限制可以具有以下含义之一-
1.它可以抛出错误或
2. 它可以简单地忽略具有该特定键的条目。

但条件是它应该在不覆盖 HashMap 的put 方法的情况下实现,并且在向给定映射添加条目时不使用if 条件。

假设我有一个 HashMap m,我想限制一个特定的字符串键 "myKey"。 我想要的是,每当我们尝试使用键“myKey”添加任何条目时,m 应该遵循上面提到的第 1 点或第 2 点。

m.put("otherKey", "value"); // should add to the map<br/>
m.put("myKey","value"); // Either throw an error or ignore this entry and should not add to the map.

我可以使用遗传学限制一种键类型,但如何针对单个给定的字符串键进行限制。这是一个面试问题。

提前致谢!!

【问题讨论】:

  • 你能详细说明为什么不能使用条件句吗?
  • 这是一道面试题……条件是不要用if

标签: java hashmap


【解决方案1】:

您可以使用 emun 作为密钥。比如

public enum AllowedKey {
    KEY_ONE,
    KEY_TWO; // etc
}

然后在你的地图中使用它:

Map<AllowedKey, String> map = new HashMap<>();
map.put("string", "value"); // compile error!
map.put(AllowedKey.KEY_ONE, "value"); // success!

如果您的实现允许,您也可以使用 EnumMap。

编辑:HashMap 的定义不能更改,因此这种方法将不再适用。

【讨论】:

    【解决方案2】:

    您有这些非常奇怪的限制......但这里没有if 声明或覆盖:

    void addToMap(HashMap<String,Sting> map, String key, String value) {
        switch (key) {
            case "MyKey":
                 throw new IllegalArgumentException(key);
            default: map.put(key, value);
        }
    }
    

    【讨论】:

    • 它按照要求执行,我想您也可以反过来执行,即map.put(sanitizeString("myKey"),value);sanitizeString 可能会引发异常。
    • 不清楚为什么 OP 需要避免 if,但如果他们有正当理由这样做,他们可能会遇到与 switch 相同的问题。此示例可能会生成与 if 相同的字节码。
    • 当然。关键是不能有任何“正当理由”来避免if statement(或为此覆盖.put)。这个问题只是作为一种谜语才有意义。就像“如何在不使用临时变量的情况下交换两个整数?” @dimo414:问题是,在您的回答中,RestrictedString 的构造函数无论如何都需要一个(等效于)if 语句。您的第一个建议涉及覆盖put if 语句,它们被禁止:)
    • @Dima 正如你所注意到的,必须有一个条件 somewhere,所以我没有提出复杂的代码,而是讨论了替代方案。 OP 反对覆盖 HashMap.put(),而不是一般覆盖(尽管这肯定是意图)。
    • switch 可以if 做同样的事情这一事实并不是一个很好的理由。您可以使用任意数量的其他控制机制来避免直接输入if,但这不是这样做的理由。
    【解决方案3】:

    您可以使用任意数量的技巧来避免显式输入if。使用switch 的现有答案有效,就像使用while 循环并在其中无条件地中断或返回一样。如果你的面试官真的想看看你如何写出令人不快的代码,那就是你的答案。

    如果您对限制HashMap 键的真实 方法感兴趣,您应该使用Guava 的ForwardingMap 并扩展 .put*() 和@ 987654333@ 方法,抛出 IllegalArgumentException "if some property of the specified key or value prevents it from being stored in this map"。即使您不使用 Guava,您也应该更喜欢 decorator pattern 而不是直接扩展 HashMapEffective Java:Item 16)。

    或者,您可能会发现为您的密钥使用专用类型更容易,例如一个 RestrictedString 类,可以进行消毒。然后您可以创建一个Map&lt;RestrictedString, String&gt; 并相信只有有效的密钥在地图中。这避免了在Map 代码中使用条件(if/switch/etc.),而是将其移至RestrictedString 类。

    即使面试官问的是一个谜题式的问题,用现实世界的解决方案来回答(同时仍然承认他们的规定)也只能在任何合法雇主那里给你加分。

    【讨论】:

    • 我喜欢装饰器模式
    • "你应该更喜欢装饰器模式而不是直接扩展 HashMap。"嗯?为什么?
    • @Dima 链接的文章讨论了装饰器模式的一些好处,但本质上它是composition over inheritance,一个标准的最佳实践。
    • @dimo414 我不会称之为“最佳实践”。继承是面向对象设计的标志性特征。放弃它以支持另一种技术不能是“最佳实践”。在这种情况下,装饰器模式只是 java 中缺少多重继承的一种解决方法。差不多,Java 8 已经过时了。
    • 让我们同意不同意,那么。但是你也反对Effective Java #16,我不会轻易这样做的。
    【解决方案4】:

    使用 Set 存储禁止的键。

    然后在一个map内映射true和false:

    Set prohibitedKeys = new HashSet<String>();
    prohibitedKeys.add("myKey");
    Map<Boolean,Map<String,String>> boolMap = new HashMap<Boolean,Map<String,String>>();
    Map<String,String> myMap = new HashMap<String,String>();
    
    boolMap.put(Boolean.FALSE,myMap);
    //This will work
    Map m = boolMap.get((Boolean)prohibitedKeys.contains("otherKey"))
    m.put("otherKey", "value");
    
    //This will throw an null pointer exception
    m.put("myKey", "value");
    

    【讨论】:

    • 这……很有创意 :) 喜欢它!
    【解决方案5】:

    EnumMap 将允许将键限制为静态子集,但显然会违反Map&lt;String, String&gt; 的要求。

    使用装饰器时,装饰器和装饰类通常共享一个接口,即 Map,因此实现自定义 put(k, v) 并将所有其他方法传递给装饰的 HashMap 可能是可以接受的,因为您没有直接覆盖 put(k, v) HashMap的方法。

    我能想到的唯一其他解决方案是使用基于 AOP 的解决方案将“之前”建议应用于 put(k, v) 方法,这将拒绝任何无效值。

    【讨论】:

      猜你喜欢
      • 2015-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-25
      • 2015-05-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多