在做项目的时候有个需求:有一个索引的集合,要求出最小的索引,索引的格式为1.10.2.4这种,即数字.数字.数字,有多少个部分不确定。我的实现如下,最早是用findMinTableIndexe2(),后来我发现每次都要对result进行split()效率不高,我想在result发生变化的时候在去split,否则就用之前的split结果,由于我写了findMinTableIndexe1(),按我的想法,应该方法1的耗时比方法2的短,因为在方法1中省去了很多的split过程,但测试的结果发现当集合的size比较小的时候(如几百内)确实方法1耗时短,但size增长后(比如几千或更大)反而方法2的耗时更短,没有明白是什么原因,请大家帮忙看下,谢谢。
代码如下,可以通过更改main()方法中的i的大小来调整集合的size.方法的参数大家可以忽略,因为实际中我要根据参数去查找到所需要的集合,在这个测试中集合已经给出。
public class FindMinIndex {
    private static Set<String> tableIndexSet = new HashSet<String>();
//    private static Logger logger = LogManager.getLogger(FindMinIndex.class);    public static void main(String[] args) {
        for (int i = 0; i < 10000; i++) {
            tableIndexSet.add(i + ".10.2.3");
            tableIndexSet.add(i + ".15.5.4");
            tableIndexSet.add(i + ".20.2.4");
            tableIndexSet.add(i + ".5.2.4");
            tableIndexSet.add(i + ".5.2.3");
            tableIndexSet.add(i + ".5.2.6");
        }
        //System.out.println(tableIndexSet.size());
        //tableIndexSet.clear();        long begin = System.currentTimeMillis();
        System.out.println(findMinTableIndexe1("1"));
        long end = System.currentTimeMillis();
        System.out.println("1 use time:" + (end - begin));
        begin = System.currentTimeMillis();
        System.out.println(findMinTableIndexe2("1"));
        end = System.currentTimeMillis();
        System.out.println("2 use time:" + (end - begin));    }    public static String findMinTableIndexe1(final String tableOid) {
        String result = null;
        boolean isResultChange = false;
        String[] partsOfResult = null;
        String[] partsOfIndex;
        for (String index : tableIndexSet) {
            try {
                if (result == null) {
                    result = index;
                    isResultChange = true;
                    continue;
                }
                partsOfIndex = index.split("\\.");
                if (isResultChange) {
                    partsOfResult = result.split("\\.");
                    isResultChange = false;
                }
                for (int i = 0; i < partsOfIndex.length; i++) {
                    if (Integer.parseInt(partsOfIndex[i]) < Integer.parseInt(partsOfResult[i])) {
                        result = index;
                        isResultChange = true;
                        break;
                    }else if(Integer.parseInt(partsOfIndex[i]) > Integer.parseInt(partsOfResult[i])){
                        break;
                    }
                }
            } catch (NumberFormatException e) {
//                logger.error("{} can not parse to Integer. You should not use this method to get the minimum index!", index);
            }
        }
        return result;
    }    public static String findMinTableIndexe2(final String tableOid) {
        String result = null;
        String[] partsOfResult = null;
        String[] partsOfIndex;
        for (String index : tableIndexSet) {
            try {
                if (result == null) {
                    result = index;
                    continue;
                }
                partsOfIndex = index.split("\\.");
                partsOfResult = result.split("\\.");
                for (int i = 0; i < partsOfIndex.length; i++) {
                    if (Integer.parseInt(partsOfIndex[i]) < Integer.parseInt(partsOfResult[i])) {
                        result = index;
                        break;
                    } else if(Integer.parseInt(partsOfIndex[i]) > Integer.parseInt(partsOfResult[i])){
                        break;
                    }
                }
            } catch (NumberFormatException e) {
//                logger.error("{} can not parse to Integer. You should not use this method to get the minimum index!", index);
            }
        }
        return result;
    }
}
java运行时间

解决方案 »

  1.   

    数据量300:
    1方法比2方法
        少了600次split
        多了300次判断
        多了1800次赋值数据量1000
    1方法比2方法
        少了2000次split
        多了1000次判断
        多了6000次赋值证明 
        1.300次判断+1800次赋值 消耗的资源 小于 600次split
        2.1000次判断+6000次赋值 消耗的资源 大于 2000次split能说明什么呢?什么也说明不了结论
        1.楼主蛋疼
        2.我也蛋疼
      

  2.   

    经过你的分析,我想了一下,方法1确实比方法2多了i*6次判断和i*6+1次赋值,而少了n次split,当i的值比较高的时候,n可能并没有变化多少(可能与hashset的存储顺序有关),所以导致出现之前结论,于是我将整个测试循环了100次,将集合改为ArrayList,并且通过Collections.shuffle()打乱顺序,结果让我找到了最根本的原因。因为我发现除了第一次的测试耗时几百,后面的时间差都是个位数,所以我发现不是由于方法1比方法2多了或少了什么操作,而是JVM对于集合或者什么其他的原因,导致第一次运行完之后已经进行了一些优化,所以方法2看起来比方法1耗时短。而当我将方法1和方法2分开运行后发现,方法1还是优于方法2!
    现在的问题是将方法1和方法2放在一起运行时,JVM到底会做什么样的优化呢?从而导致后面的运行会更快,我想有点太深入了,希望有人能解答吧。
      

  3.   

    昨天想了一下,可能是因为string共享池的原因吧,第二次运行时很多string对象已经存在在共享池吧,因此省去了创建对象的消耗。总之现在没啥问题了,感谢1楼的讨论