说说java中传容器某些情况下失效

Posted 岁月_匆匆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了说说java中传容器某些情况下失效相关的知识,希望对你有一定的参考价值。

   楼主今天写个方法移除map集合中的空值,遇到个问题,就是对容器操作后,发现失效了;先上代码

public static void removeValueNullAndEmpty(Map<String,String> A) {
        Map<String,String> B = new HashMap<>();
        for(String key : B.keySet()){
            if(A.get(key) != null || !"".equals(A.get(key))){
                B.put(key, A.get(key));
            }
        }
        A=B;
    }
public static void main(String[] args) {
        Map<String,String> B = new HashMap<>();
        B.put("c", "3");
        B.put("d", "");
        B.put("e", null);
        removeValueNullAndEmpty(B);
        System.out.println(B);
}

就是这么个操作,结果当然很尴尬;

{c=3, d=, e=null}

怎么回事呢?这就要说到函数的调用了,在main函数调用removeValueNullAndEmpty的时候,保存现场,保存了B的地址;我们姑且看做addressB吧,也就是说main函数任务B = addressB;然后就把addressB传给了removeValueNullAndEmpty方法,而removeValueNullAndEmpty方法的一系列处理其实并没有改变addressB这个地址指向的空间内的任何数据;而是简单的把B这个字面量指向的地址换成了addressB;然后结束了removeValueNullAndEmpty方法;在此之后,回到main方法,而main方法依然认为B = addressB,为什么呢?这是因为我们在removeValueNullAndEmpty方法中改变的那个字面量B已经随着removeValueNullAndEmpty方法的结束而被关闭了,根本就和main方法没有任何关系,所以main方法下面的输出语句依然会输出addressB所指向空间内的值。就是这么简单。

 

找到了问题自然要解决啊,但是我又不想通过return来返回,就是希望B这个map过一趟removeValueNullAndEmpty方法就把没用的东西给丢掉了;怎么办呢?我首先是在原来的代码上随便做了点修改

public static void removeValueNullAndEmpty(Map<String,String> A) {
        for(String key : A.keySet()){
            if(A.get(key) == null || "".equals(A.get(key))){
                A.remove(key);
            }
        }
    }

这样当然不行了,一执行就报错了

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.HashMap$HashIterator.nextNode(Unknown Source)
    at java.util.HashMap$KeyIterator.next(Unknown Source)
    at test.Main.removeValueNullAndEmpty(Main.java:28)
    at test.Main.main(Main.java:52)

这一看就晓得了,keySet()拿出来的是个set视图,这只是一个与map中键的映射;如果remove掉原map集合中的一个元素,就会影响到keySet()取到的set视图的内容,进而影响到后续元素的获取,所以这么做是不被允许的,那么只能想其他办法了。这时候,我想到了迭代器

public static void removeValueNullAndEmpty(Map<String,String> A) {
        Iterator<String> iterator = A.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            if(A.get(key) == null || "".equals(A.get(key))){
                iterator.remove();
            }
            
        }
    }
    
    
    public static void main(String[] args) {
        Map<String,String> B = new HashMap<>();
        B.put("c", "3");
        B.put("d", "");
        B.put("e", null);
        removeValueNullAndEmpty(B);
        System.out.println(B);
        }

执行之后,就灰常正常了。

{c=3}

ok,其实不是多大的问题,主要是对集合不熟悉的锅就这样吧

以上是关于说说java中传容器某些情况下失效的主要内容,如果未能解决你的问题,请参考以下文章

CentOS7下Docker重启容器后防火墙因重置失效的解决方式

CentOS7下Docker重启容器后防火墙因重置失效的解决方式

技术点:迭代器失效的几种情况

C++迭代器失效的几种情况总结

java中传值及引伸深度克隆的思考(说白了Java只能传递对象指针)

github代码导航失效