解决迭代集合出现ConcurrentModificationException问题

 

 

 

 

太懒不准备再写demo,直接项目上的代码。。。

public String getSvcsWithNamespaceAndDeployment(ProxyAuth auth, String clusterId, String namespace,String deployment) {
     log.info("获取集群ID:{},命名空间:{},deploy:{},对应svc",clusterId,namespace,deployment);
     List<io.fabric8.kubernetes.api.model.Service> services = kubernetesAPI.getServicesNew(auth, clusterId, namespace, null);
     Deployment deploy = kubernetesAPI.getDeployment(auth, clusterId, namespace, deployment);
     List<io.fabric8.kubernetes.api.model.Service> svc = Lists.newArrayList();
     services.forEach(service -> {
         AtomicBoolean match = new AtomicBoolean(true);
         Map<String,String> maps = service.getSpec().getSelector();
         Map<String,String> des = deploy.getSpec().getSelector().getMatchLabels();
         des.forEach((k,v) -> {
             if(null != maps) {
                 String value = maps.get(k);
                 if(value == null || !value.equals(v)) {
                     match.set(false);
                     return;
                 }
             }else{
                 match.set(false);
                 return;
             }
         });
         if(match.get()) {
             svc.add(service);
         }
     });
     ObjectMapper mapper = new ObjectMapper();
     try {
        String json =  mapper.writeValueAsString(svc);
        return json;
     } catch (JsonProcessingException e) {
         e.printStackTrace();
     }
     log.info("获取svc:{}",svc);
     return null;
 }

之前某位码哥写的代码,其实业务还是挺简单的,但是由于要避免迭代list的时候删除元素出问题,他的做法是新创建了一个集合,然后又搞了一个标志位,当标志位为true的时候把数据放入新的集合中,说实话挺麻烦,而且代码可读性差。

所以对代码进行了第一次优化,首先想到的是CopyOnWriteArrayList这个类,这是一个线程安全的集合类采用的是读写分离,在迭代的时候是可以删除元素的,好处是省略了标志位并且可读性稍高,代码如下

public List<io.fabric8.kubernetes.api.model.Service> getSvcsWithNamespaceAndDeployment(ProxyAuth auth, String clusterId, String namespace,String deployment) {
    log.info("获取集群ID:{},命名空间:{},deploy:{},对应svc",clusterId,namespace,deployment);
    List<io.fabric8.kubernetes.api.model.Service> services = kubernetesAPI.getServicesNew(auth, clusterId, namespace, null);
    CopyOnWriteArrayList<io.fabric8.kubernetes.api.model.Service> svcs = new CopyOnWriteArrayList(services.toArray());
    Deployment deploy = kubernetesAPI.getDeployment(auth,clusterId,namespace,deployment);
    svcs.forEach(service -> {
        Map<String,String> maps = service.getSpec().getSelector();
        if(null != maps) {
            deploy.getSpec().getSelector().getMatchLabels().forEach((k,v) -> {
                String value = maps.get(k);
                if(value == null || !value.equals(v)) {
                    svcs.remove(service);
                    return;
                }
            });
        }else{
            svcs.remove(service);
            return;
        }
    });
    log.info("获取deployment对应的svc:{}",svcs);
    return svcs;
}

想到都用stream流编程了,使用filter进行过滤下吧,代码如下

public List<io.fabric8.kubernetes.api.model.Service> getSvcsWithNamespaceAndDeployment(ProxyAuth auth, String clusterId, String namespace,String deployment) {
    log.info("获取集群ID:{},命名空间:{},deploy:{},对应svc",clusterId,namespace,deployment);
    List<io.fabric8.kubernetes.api.model.Service> services = kubernetesAPI.getServicesNew(auth, clusterId, namespace, null);
    Deployment deploy = kubernetesAPI.getDeployment(auth,clusterId,namespace,deployment);
    List<io.fabric8.kubernetes.api.model.Service> svcs = services.stream()
            .filter(service -> null != service.getSpec().getSelector())
            .filter(service -> deploy.getSpec().getSelector().getMatchLabels()
                    .entrySet().stream().anyMatch(entry -> {
                        String value = service.getSpec().getSelector().get(entry.getKey());
                        return null != value && value.equals(entry.getValue());
                    })
            )
            .collect(Collectors.toList());
    log.info("获取deployment对应的svc:{}",svcs);
    return svcs;
}

原来的foreach使用的是外部迭代,stream中的迭代是内部迭代没有迭代器iterator,如果数据量比较大处理比较繁琐的时候内部迭代效率会比较高。stream中也有foreach,它是一个终端操作,在里面进行不了元素更改的操作,所以只能用filter(中端操作)进行过滤。明显发现使用stream编程代码可读性比之前高不少。

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值