Java 如果键存在且值不为null,则放入映射,否则抛出异常

Java 如果键存在且值不为null,则放入映射,否则抛出异常,java,java-8,hashmap,Java,Java 8,Hashmap,我可以用Java8以更好的方式编写它吗?我可以用某种方式将其合并为一个表达式吗?记住,要求是: 如果键存在或值不为null,则放入映射,否则抛出异常 这意味着: 如果密钥不存在,则抛出异常 若值为null,则引发异常 放在地图上 您应该首先执行null检查,然后使用该方法并检查返回值,因此只执行一次映射查找 void addToMapIfKeyExists(String k, String v) { if (!map.containsKey(k)) { throw n

我可以用Java8以更好的方式编写它吗?我可以用某种方式将其合并为一个表达式吗?

记住,要求是:

如果键存在或值不为null,则放入映射,否则抛出异常

这意味着:

  • 如果密钥不存在,则抛出异常
  • 若值为null,则引发异常
  • 放在地图上
您应该首先执行null检查,然后使用该方法并检查返回值,因此只执行一次映射查找

void addToMapIfKeyExists(String k, String v) {
    if (!map.containsKey(k)) {
        throw new NoSuchElementException(k + " does not exist in the map");
    }

    // else ignore
    if (v != null) {
        map.put(k, v);
    }
}

您可以在一条语句中:

void addToMapIfKeyExists(String k, String v) {
    if (v == null)
        throw new IllegalArgumentException("Value is null");
    if (map.replace(k, v) == null)
        throw new NoSuchElementException("Key doesn't exist: " + k);
}
上述规定:

[1] 如果键不在映射中,或者映射为null,则会抛出
NoTouchElementException

[2] 否则,如果您试图设置
null
,则不会执行任何操作

[3] 否则,将键设置为新值


这显然是您想要的,但这是一个奇怪的需求组合。

在最简单的形式中,如下内容可能适合您的需要:

public void overwrite(String k, String v) {
    map.compute(k, (key, value) -> {
        if (value == null) throw new NoSuchElementException(key + " does not exist in the map");
        return v == null ? value : v;
    });
}

免责声明:选择此项之前,请明智地做出决定。我将建议将此作为基于所涉及API的实践

static void addToMapIfKeyExists(String k, String v) {
    if (v != null && map.containsKey(k)) { // if key exists and value is not null
        map.put(k, v); // Put in the map 
    } else { // else throw exception
        throw new IllegalArgumentException("Else throwing exception.");
    }
}
我可以通过以下测试比较这两种方法的行为是否相同:

static void addToMapIfKeyExistsOneLiner(String k, String v) {
    map.put(k, Optional.ofNullable(v)
            .filter(ignore -> map.containsKey(k))
            .orElseThrow(IllegalArgumentException::new));
}
staticmap=newhashmap();
私有静态void comparativeTest(){
放在地图上(“a”,“trying”);
地图。放(“b”,“哭”);
addToMapIfKeyExists(“a”,“works”);
System.out.println(map.get(“a”).equals(“works”);
添加到PIFKEYEXISTSONELINER(“a”,“作品”);
System.out.println(map.get(“a”).equals(“works”);
AddToMapFKeyExists(“b”,null);//null值引发异常
addToMapIfKeyExists(“e”,“新键抛出异常”);
addToMapIfKeyExistsOneLiner(“b”,null);//null值引发异常
addtomapifkeyxistsoneliner(“e”,“新键抛出异常”);
}

@Kayaman,我已经更新并更改了一点问题,有什么想法吗?默认V替换(K键,V值)仅当指定键当前映射到某个值时才替换该项。这不适合你吗?小心替换。检查“returns”中的解释,除了值为
null
时的异常处理之外,您已经拥有的已经足够好了,只是需求看起来有点奇怪。这就好像
putIfPresent
与正常的
put
异常处理一样。你为什么说奇怪?它更原子化。如果地图做出了某些原子保证,则上述内容将是原子的。一个if/else不能被地图原子化,它永远不能知道第二个调用即将到来。这些东西的性能取决于虚拟机、操作系统,尤其是map impl,没有一个答案。对于大多数映射来说,这不会造成任何性能差异。如果更新操作只是在键不在映射中时写入,则更有意义。如果它真的没有覆盖(如果它已经存在的话),那么null处理就很奇怪:如果我想用null覆盖,那么它应该这样做(用null替换该值,或者可能删除该值)。请注意,计算返回“null”意味着:删除。普通的
HashMap
不保证原子性,但是单个
compute
可能比
containsKey
后跟
put
更有效,因为它只支持单个哈希查找。您还可以使用
if(map.compute(k,(key,value)->v==null?value:v==null)抛出新的NoSuchElementException(key+“在映射中不存在”);此变量还可用于
computeIfPresent
。当
键不存在时,此变量将执行
put
,并更新现有的
映射。除了“A
null
return还可以指示先前将
null
与键关联的映射..”@nama关于
null
返回值是正确的,但是对该方法的要求将指示不允许
null
值,这非常适合
map
上的较新方法,类似于
replace()
,它将
null
值视为不存在的条目。同意将共享实现与
null
值处理对齐。但是作为
replace
的一个副作用,更新映射超出了
addToMapIfKeyExists
的目的。因此,您对这两个问题的回答都是“否”,即问题:“我可以在Java 8中以更好的方式编写它吗?”和“我可以以某种方式将其合并到一个表达式中吗?”,因为此代码基本上与问题代码相同,除了你修复了异常抛出的问题。@Andreas我想也有解决的办法。但主要是滥用了来自JDK的另一个API。所以我不能完全说“不”,谢谢@Naman。您能将您的一行代码与我几个小时前接受的答案进行比较吗?@HarshalParekh我建议您编写一个单元测试,并根据比较这里各种实现的期望进行断言,然后您可以根据您所感觉到的可读性来决定哪个适合您的需要。@Naman,我指的是性能,而不是准确性。很抱歉给你带来了困惑。
static Map<String, String> map = new HashMap<>();

private static void comparativeTest() {
    map.put("a", "trying");
    map.put("b", "crying");

    addToMapIfKeyExists("a", "works");
    System.out.println(map.get("a").equals("works"));

    addToMapIfKeyExistsOneLiner("a", "works");
    System.out.println(map.get("a").equals("works"));


    addToMapIfKeyExists("b", null); // null value throw exception
    addToMapIfKeyExists("e", "new key throws exception");

    addToMapIfKeyExistsOneLiner("b", null); // null value throw exception
    addToMapIfKeyExistsOneLiner("e", "new key throws exception");
}