• 引用对象的使用和易产生bug的示例


    本文属原创,转载请注明出处:http://www.cnblogs.com/robinjava77/p/5481608.html  (Robin)

    QuoteTest(引用对象技巧)  

      1 import java.util.ArrayList;
      2 import java.util.HashMap;
      3 import java.util.List;
      4 import java.util.Map;
      5 
      6 /**
      7  * Created by robin on 2016/4/13.
      8  * 引用型对向操作总结:
      9  * 1.被引用的对象,值改变时,会直接改变引用源的值;
     10  * 2.当引用的对象,改变其引用源时,对其操作,只会改变新的引用源的值,并不会影响之前的引用源的值
     11  * 3.从map中获取的引用不存在时,需要将新的引用put到map中,map中该位置的值,才会被引入
     12  * @author robin
     13  */
     14 public class QuoteTest {
     15 
     16     public static void main(String args[]){
     17         Map<String,List<String>> map = new HashMap<String, List<String>>();
     18         for (int i =0;i< 5;i++){
     19             List<String> datalist = new ArrayList<String>();
     20             for (int j=0;j<10;j++){
     21                 datalist.add(i*10+""+j);
     22             }
     23             map.put(""+i,datalist);
     24         }
     25         for (List<String> list:map.values()){
     26             System.out.println(listToString(list));
     27         }
     28         System.out.println("----------分隔线1-----------");
     29         List<String> tempList =  map.get("3");
     30         tempList.add("avc");
     31         tempList.remove("300");
     32         for (List<String> list:map.values()){
     33             System.out.println(listToString(list));
     34         }
     35         System.out.println("----------分隔线2-----------");
     36         List<String> tempList2 =  map.get("2");//tempList 获得map中 key为2的引用
     37         List<String> replaceList = new ArrayList<String>();
     38         tempList2 = replaceList;////tempList 获得其他list的引用,失去map中 key为2的引用,此时对templist2做任何操作,影响的时replaceList引用的区域
     39         tempList2.add("replaceList的值被改变");
     40         for (List<String> list:map.values()){
     41             System.out.println(listToString(list));
     42         }
     43         System.out.println("replaceList的值:"+listToString(replaceList));
     44         System.out.println("----------分隔线3-----------");
     45         List<String> tempList3 =  map.get("2");
     46         tempList3 = replaceList;
     47         map.put("2",tempList3);
     48         for (List<String> list:map.values()){
     49             System.out.println(listToString(list));
     50         }
     51         System.out.println("----------分隔线4-----------");
     52         List<String> notExistList = map.get("5");
     53         if(notExistList == null){
     54             notExistList = new ArrayList<String>();
     55         }
     56         notExistList.add("第5行数据添加进来...");
     57         for (List<String> list:map.values()){
     58             System.out.println(listToString(list));
     59         }
     60         System.out.println("----------分隔线5-----------");
     61         List<String> notExistList2 = map.get("6");
     62         if(notExistList2 == null){
     63             notExistList2 = new ArrayList<String>();
     64         }
     65         notExistList2.add("第6行数据添加进来...");
     66         map.put("6",notExistList2);
     67         for (List<String> list:map.values()){
     68             System.out.println(listToString(list));
     69         }
     70         System.out.println("----------分隔线5-----------");
     71 
     72         Map<String,Map<String,String>> mapOne = new HashMap<String, Map<String, String>>();
     73         String keyss = "mapTest";
     74         Map<String,String> mapTwo = new HashMap<String, String>();
     75         mapOne.put(keyss,mapTwo);
     76         System.out.println("mapOne的数据:" + mapToString(mapOne));
     77         System.out.println("----------分隔线6-----------");
     78         mapTwo.put("aaa", "aaav");
     79         mapTwo.put("bbb", "bbbv");
     80         mapTwo.put("ccc","cccv");
     81         System.out.println("mapOne的数据:"+mapToString(mapOne));
     82         System.out.println("----------分隔线7-----------");
     83     }
     84 
     85     private static String listToString(List<String> list){
     86         StringBuilder sb = new StringBuilder("");
     87         for (String s:list){
     88             sb.append("["+s+"] ");
     89         }
     90         return sb.toString();
     91     }
     92 
     93     private static String mapToString(Map<?,?> map){
     94         StringBuilder sb = new StringBuilder("");
     95         for(Map.Entry entry:map.entrySet()){
     96             sb.append("[key:"+entry.getKey()+";value:"+entry.getValue()+"]");
     97         }
     98         return sb.toString();
     99     }
    100 
    101 }

    ---------------------

    引用对象易产生的bug:

    2016.05.11

    关于引用对象,使用不恰当,很容易给自己挖坑,产生非常严重的bug,进而导致整个系统实际业务的崩溃,而且这种bug很难被查出来。(如果日志记录不够详细,分析不够彻底,要找出这种bug,只能靠上帝保佑)

    下面先上bug 代码 demo

     1 import java.util.Iterator;
     2 import java.util.List;
     3 import java.util.Vector;
     4 
     5 /**
     6  * Created by robin on 2016/5/11.
     7  *
     8  * @author robin
     9  */
    10 public class QuoteBugDemo {
    11 
    12     private static List<Integer> publicNums = new Vector<Integer>();
    13 
    14     public static void main(String args[]) throws InterruptedException {
    15         initPublicNums();//初始化公共数据源
    16 
    17         timeTask(1);//模拟执行定时任务1
    18 
    19         timeTask(2);//模拟执行定时任务2
    20 
    21     }
    22 
    23 
    24     private static void initPublicNums(){
    25         for (int i =0;i < 10;i++){
    26             publicNums.add(i);
    27         }
    28     }
    29 
    30     /**
    31      * 这块代码模拟的逻辑:
    32      * 1.每天获取配置好10个的数据源;
    33      * 2.检查这10个数据源,当数据源的数据准备好后,开始执行数据同步;
    34      * 3.从当天的带同步数据源list删除已经同步的数据;
    35      * @param mark
    36      * @throws InterruptedException
    37      */
    38     private static void timeTask(int mark) throws InterruptedException {
    39         final long start = System.currentTimeMillis();//程序开始运行时间
    40         //每天待同步数据源
    41         List<Integer> dataSources = publicNums;
    42         StringBuffer sb = new StringBuffer("mark("+mark+");公共数据源数目:"+dataSources.size()+";数据源列表[");
    43         for (Integer i:dataSources){
    44             sb.append(i+",");
    45         }
    46         sb.append("]");
    47         System.out.println("日志【"+sb.toString()+"】");
    48         while(true){
    49             long seconds = (System.currentTimeMillis() - start) / 1000;
    50             if(seconds > 15l){
    51                 System.out.println("运行超过限定时间:15秒,退出");
    52                 break;
    53             }
    54             Iterator<Integer> ite = dataSources.iterator();
    55             while (ite.hasNext()){//
    56                 int dataSource = ite.next();
    57                 boolean flag = isOk(dataSource);
    58                 if(flag){//数据源数据已准备好
    59                     System.out.println("对数据源:"+dataSource+"进行数据处理。");//同步数据
    60                     ite.remove();//待同步数据源删除该数据源
    61                 }
    62             }
    63             if(dataSources.size() != 0){
    64                 Thread.sleep(1000);
    65             }else{
    66                 break;
    67             }
    68         }
    69         System.out.println("定时任务mark["+mark+"]已经执行完毕");
    70     }
    71 
    72     /**
    73      * 模拟检查数据源是否OK
    74      * @param dataSource
    75      * @return
    76      */
    77     private static boolean isOk(int dataSource){
    78         if(dataSource%2 == 0){
    79             return true;
    80         }
    81         return false;
    82     }
    83 
    84 
    85 }

    执行结果:

     1 日志【mark(1);公共数据源数目:10;数据源列表[0,1,2,3,4,5,6,7,8,9,]】
     2 对数据源:0进行数据处理。
     3 对数据源:2进行数据处理。
     4 对数据源:4进行数据处理。
     5 对数据源:6进行数据处理。
     6 对数据源:8进行数据处理。
     7 运行超过限定时间:15秒,退出
     8 定时任务mark[1]已经执行完毕
     9 日志【mark(2);公共数据源数目:5;数据源列表[1,3,5,7,9,]】
    10 运行超过限定时间:15秒,退出
    11 定时任务mark[2]已经执行完毕

    定时任务2,执行的时候,数据源只剩1,3,5,7,9。

    改进方案:将公共数据源保护起来,仅提供公共数据源的副本:shallow copy和deep copy

    核心代码:

    1 /**
    2      * 改进方案1:获取公共数据源对象的副本
    3      * shallow copy:list中 元素引用 仍然是相同的
    4      * @return
    5      */
    6     private static List<Integer> getPublicNums(){
    7         List<Integer> clone = new ArrayList<Integer>(publicNums);
    8         return clone;
    9     }

    改进后全部代码:

     1 import java.util.ArrayList;
     2 import java.util.Iterator;
     3 import java.util.List;
     4 import java.util.Vector;
     5 
     6 /**
     7  * Created by robin on 2016/5/11.
     8  *
     9  * @author robin
    10  */
    11 public class QuoteBugDemo {
    12 
    13     private static List<Integer> publicNums = new Vector<Integer>();
    14 
    15     public static void main(String args[]) throws InterruptedException {
    16         initPublicNums();//初始化公共数据源
    17 
    18         timeTask(1);//模拟执行定时任务1
    19 
    20         timeTask(2);//模拟执行定时任务2
    21 
    22     }
    23 
    24 
    25     private static void initPublicNums(){
    26         for (int i =0;i < 10;i++){
    27             publicNums.add(i);
    28         }
    29     }
    30 
    31     /**
    32      * 改进方案1:获取公共数据源对象的副本
    33      * shallow copy:list中 元素引用 仍然是相同的
    34      * @return
    35      */
    36     private static List<Integer> getPublicNums(){
    37         List<Integer> clone = new ArrayList<Integer>(publicNums);
    38         return clone;
    39     }
    40 
    41     /**
    42      * 这块代码模拟的逻辑:
    43      * 1.每天获取配置好10个的数据源;
    44      * 2.检查这10个数据源,当数据源的数据准备好后,开始执行数据同步;
    45      * 3.从当天的带同步数据源list删除已经同步的数据;
    46      * @param mark
    47      * @throws InterruptedException
    48      */
    49     private static void timeTask(int mark) throws InterruptedException {
    50         final long start = System.currentTimeMillis();//程序开始运行时间
    51         //每天待同步数据源
    52         List<Integer> dataSources = getPublicNums();//改进方案1
    53         StringBuffer sb = new StringBuffer("mark("+mark+");公共数据源数目:"+dataSources.size()+";数据源列表[");
    54         for (Integer i:dataSources){
    55             sb.append(i+",");
    56         }
    57         sb.append("]");
    58         System.out.println("日志【"+sb.toString()+"】");
    59         while(true){
    60             long seconds = (System.currentTimeMillis() - start) / 1000;
    61             if(seconds > 15l){
    62                 System.out.println("运行超过限定时间:15秒,退出");
    63                 break;
    64             }
    65             Iterator<Integer> ite = dataSources.iterator();
    66             while (ite.hasNext()){//
    67                 int dataSource = ite.next();
    68                 boolean flag = isOk(dataSource);
    69                 if(flag){//数据源数据已准备好
    70                     System.out.println("对数据源:"+dataSource+"进行数据处理。");//同步数据
    71                     ite.remove();//待同步数据源删除该数据源
    72                 }
    73             }
    74             if(dataSources.size() != 0){
    75                 Thread.sleep(1000);
    76             }else{
    77                 break;
    78             }
    79         }
    80         System.out.println("定时任务mark["+mark+"]已经执行完毕");
    81     }
    82 
    83     /**
    84      * 模拟检查数据源是否OK
    85      * @param dataSource
    86      * @return
    87      */
    88     private static boolean isOk(int dataSource){
    89         if(dataSource%2 == 0){
    90             return true;
    91         }
    92         return false;
    93     }
    94 
    95 
    96 }

    执行结果:

     1 日志【mark(1);公共数据源数目:10;数据源列表[0,1,2,3,4,5,6,7,8,9,]】
     2 对数据源:0进行数据处理。
     3 对数据源:2进行数据处理。
     4 对数据源:4进行数据处理。
     5 对数据源:6进行数据处理。
     6 对数据源:8进行数据处理。
     7 运行超过限定时间:15秒,退出
     8 定时任务mark[1]已经执行完毕
     9 日志【mark(2);公共数据源数目:10;数据源列表[0,1,2,3,4,5,6,7,8,9,]】
    10 对数据源:0进行数据处理。
    11 对数据源:2进行数据处理。
    12 对数据源:4进行数据处理。
    13 对数据源:6进行数据处理。
    14 对数据源:8进行数据处理。
    15 运行超过限定时间:15秒,退出
    16 定时任务mark[2]已经执行完毕

    已达预期。

    ------------------------------------------

    shallow copy 和 deep copy 的区别详见我的另一篇博客:http://www.cnblogs.com/robinjava77/p/5481874.html 

  • 相关阅读:
    spring boot banner设置关闭以及关闭特定的自动配置
    spring boot 初始及快速搭建
    spring scheduling 计划任务
    idea database 导入实体带注解
    idea mapper下的方法找不到 Invalid bound statement (not found)
    spring jwt token 认证
    spring event 事件
    FrontEnd-Basis-6th
    FrontEnd-Basis-5th
    FrontEnd-Basis-4th
  • 原文地址:https://www.cnblogs.com/robinjava77/p/5481608.html
Copyright © 2020-2023  润新知