Java 8集合映射从集合中删除元素,如果为空,则删除条目

Java 8集合映射从集合中删除元素,如果为空,则删除条目,java,dictionary,collections,java-8,hashmap,Java,Dictionary,Collections,Java 8,Hashmap,我有一个值为集合的映射。给定一个键,我想删除集合的一个元素并返回它,但如果集合为空,我还想删除该项。使用Java8的众多新映射方法中的一种,有没有一种方法可以简单地做到这一点 一个简单的例子(我使用堆栈,但它可以是列表、集合等)。在本例中,假设已经检查映射是否包含密钥 public static String removeOne(Map<Integer, Stack<String>> map, int key) { Stack<String> stac

我有一个值为集合的映射。给定一个键,我想删除集合的一个元素并返回它,但如果集合为空,我还想删除该项。使用Java8的众多新映射方法中的一种,有没有一种方法可以简单地做到这一点

一个简单的例子(我使用堆栈,但它可以是列表、集合等)。在本例中,假设已经检查映射是否包含密钥

public static String removeOne(Map<Integer, Stack<String>> map, int key) {
    Stack<String> stack = map.get(key);
    String result = stack.pop();
    if(stack.isEmpty()){
        map.remove(key);
    }
    return result;
}
但即使它确实删除了空条目,我也不知道如何获取
pop()
返回的值

/*相当难看
字符串rv=可选的.ofNullable(map.get(1)).map(堆栈->{
如果(!stack.isEmpty()){
String v=stack.pop();
if(stack.isEmpty()){
地图。删除(1);
}
返回v;
}
返回null;
}).orElse(空);
*/ 
@试验
公开无效测试(){
{
Map Map=newhashmap();
堆栈s=新堆栈();
s、 addAll(Arrays.asList(“a”、“b”);
地图.put(1,s);;
字符串rv=可选的.ofNullable(map.get(1)).map(堆栈->{
如果(!stack.isEmpty()){
String v=stack.pop();
if(stack.isEmpty()){
地图。删除(1);
}
返回v;
}
返回null;
}).orElse(空);
Assert.assertEquals(“b”,rv);
Assert.assertEquals(1,map.get(1.size());
Assert.assertEquals(“a”,map.get(1.iterator().next());
}
{
Map Map=newhashmap();
堆栈s=新堆栈();
s、 添加(“a”);
地图.put(1,s);;
字符串rv=可选的.ofNullable(map.get(1)).map(堆栈->{
如果(!stack.isEmpty()){
String v=stack.pop();
if(stack.isEmpty()){
地图。删除(1);
}
返回v;
}
返回null;
}).orElse(空);
Assert.assertEquals(“a”,rv);
Assert.assertNull(map.get(1));
}
}

好吧,它甚至比你现有的还要丑陋,但我想有一种方法:

public static String removeOne(Map<Integer, Stack<String>> map, int key) {
    String[] removed = new String[1];
    map.compute(key, (k, v) -> {
        removed[0] = v.pop();
        return v.size() == 0 ? null : v;
    });
    return removed[0];
}
publicstaticstringremoveone(映射映射,int键){
字符串[]已删除=新字符串[1];
map.compute(键,(k,v)->{
删除[0]=v.pop();
返回v.size()==0?空:v;
});
删除返回[0];
}
问题是
merge/compute
等返回值,在您的例子中,它是
Stack/Set/List
,而不是该集合中的单个元素

有没有一种方法可以使用众多的新方法中的一种以简短的方式做到这一点 Java8的映射方法

从JDK8开始,没有新的方法可以提高代码的可读性或效率

如果你这样做是为了锻炼自己,那么我在某种程度上可以理解为什么你想缩短代码(如果可能的话),但是当涉及到生产代码时,应该避免打高尔夫,而是采用最可读和可维护的方法;长一点也不要紧


你的方法很好

我完全同意@NicholasK。这里没有理由使用任何流或lambda

你的方法很好。我想补充的唯一一点是使其通用:

public static <K, E, C extends Collection<E>> E removeOne(Map<K, C> map, K key) {
    C col = map.get(key);
    Iterator<E> it = col.iterator();
    E e = it.next();
    it.remove();
    if (!it.hasNext()) {
        map.remove(key);
    }
    return e;
}
public static E removeOne(地图地图,K键){
C col=map.get(键);
迭代器it=列迭代器();
E=it.next();
it.remove();
如果(!it.hasNext()){
地图。删除(键);
}
返回e;
}
此方法将适用于返回有效迭代器的任何集合(映射值)。

为您处理删除集合(如果为空)逻辑。您可以在两行中获得与方法相同的行为:

public static String removeOne(ListMultimap<Integer, String> map, int key) {
    List<String> stack = map.get(key);
    return stack.remove(stack.size() - 1);
}
publicstaticstringremoveone(ListMultimap映射,int键){
列表堆栈=map.get(键);
返回stack.remove(stack.size()-1);
}
如果映射没有给定键的条目,则现有解决方案和上述解决方案都会引发异常。或者,您可以更改代码以处理此问题:

public static String removeOne(ListMultimap<Integer, String> map, int key) {
    List<String> stack = map.get(key);
    if (stack.isEmpty()) {
        return null;
    }
    return stack.remove(stack.size() - 1);
}
publicstaticstringremoveone(ListMultimap映射,int键){
列表堆栈=map.get(键);
if(stack.isEmpty()){
返回null;
}
返回stack.remove(stack.size()-1);
}
当然,你也可以把它变成通用的:

public static <K, V> V removeOne(ListMultimap<K, V> map, K key) {
    List<V> stack = map.get(key);
    if (stack.isEmpty()) {
        return null;
    }
    return stack.remove(stack.size() - 1);
}
publicstaticv removeOne(ListMultimap映射,K键){
列表堆栈=map.get(键);
if(stack.isEmpty()){
返回null;
}
返回stack.remove(stack.size()-1);
}

或者您可以使用
大小将其重写为:

public static String removeOne(Map<Integer, Stack<String>> map, int key) {
    return map.get(key).size() == 1 ? map.remove(key).pop() : map.get(key).pop();
}
publicstaticstringremoveone(映射映射,int键){
return map.get(key).size()==1?map.remove(key).pop():map.get(key).pop();
}

@jurgendlandsheer您首先需要
弹出
,然后检查它是否为空。它完全按照他的要求执行,并且使用了所有新的java 8可能性。我真的不认为有任何理由在这里使用streams/lambda。@NicholasK唯一的优点是映射为null并自动删除条目IMO,否则,我不得不同意,我不确定这会有多普遍,但是怎么样?哈哈哈,我确实想过这个解决方案,但正如你所说的,它真的很难看。如果集合为空,我找不到删除条目的部分。另外,您必须执行
it.remove()
在所有情况下,为什么要执行
!it.hasNext()
检查?
!it.hasNext()
在我们删除元素后检查集合是否为空,正如OP在他自己的示例中实现的那样。我是OP,我100%确信这不会做同样的事情。我刚测试过。正如我所说的,您永远不会从地图中删除空集合。我想你的意思是:
if(!it.hasNext()){map.remove(key);}it.remove()好的,我站着更正。现在更新的版本也应该这样做
public static <K, V> V removeOne(ListMultimap<K, V> map, K key) {
    List<V> stack = map.get(key);
    if (stack.isEmpty()) {
        return null;
    }
    return stack.remove(stack.size() - 1);
}
public static String removeOne(Map<Integer, Stack<String>> map, int key) {
    return map.get(key).size() == 1 ? map.remove(key).pop() : map.get(key).pop();
}