Collections排序

0.前言

ThreeSet的底层实现是红黑树,它在创建set的过程中实现排序。Collections.sort是在对整个集合进行排序,按道理来说使用TreeSet插入集合元素直至建立整个TreeSet过程中实现排序在时间方面要比Collections.sort对整个集合进行排序效率要高很多,因为它在每次搜索要插入的位置时耗费的时间为log(n),n代表的是当前集合的长度,但实验表明使用Collections.sort对集合进行排序时间耗费要少些。

返回类型为int型

        Collections.sort(appIds, new Comparator<AfaApplication>() {
              @Override
              public int compare(AfaApplication app1, AfaApplication app2) {
                  if(StringUtils.isNotNullAndBlank(app1.getAppId())&&StringUtils.isNotNullAndBlank(app2.getAppId())){
                      return Integer.parseInt(app1.getAppId())-Integer.parseInt(app2.getAppId());
                  }else{
                      return 0;
                  }
              }
        });        

有时候会报错

java.lang.NumberFormatException: For input string: "006006003002"

有几种可能,有可能字段转换值超了,有可能获取的字段为空或者为null无法转为数据,这时候就要判断为空或者null

值超了和null的情况处理:

        Collections.sort(appMenuTreeList, new Comparator<AppMenuTree>() {
              @Override
              public int compare(AppMenuTree tree1, AppMenuTree tree2) {
                  if(StringUtils.isNotNullAndBlank(tree1.getTreeId())&&StringUtils.isNotNullAndBlank(tree2.getTreeId())){
                      return Long.parseLong(tree1.getTreeId())>Long.parseLong(tree2.getTreeId())?1:-1;
                  }else{
                      return 0;
                  }
              }
        });

有时候会报错

Comparison method violates its general contract
      Collections.sort(appMenuTreeList, new Comparator<AppMenuTree>() {
              @Override
              public int compare(AppMenuTree tree1, AppMenuTree tree2) {
                  if(StringUtils.isNotNullAndBlank(tree1.getTreeId())&&StringUtils.isNotNullAndBlank(tree2.getTreeId())){
             if(Long.parseLong(tree1.getTreeId())==Long.parseLong(tree2.getTreeId())){
                  return 0;
                }else{
                           return Long.parseLong(tree1.getTreeId())>Long.parseLong(tree2.getTreeId())?1:-1;
              } }
else{ return 0; } } });
        Collections.sort(roleList, new Comparator<AfaRole>() {
            @Override
            public int compare(AfaRole tree1, AfaRole tree2) {
                if(StringUtils.isNotNullAndBlank(tree1.getRoleCode())&&StringUtils.isNotNullAndBlank(tree1.getRoleCode())){
                    return tree1.getRoleCode().compareToIgnoreCase(tree2.getRoleCode());
                }else{
                    return 0;
                }
            }
        });

1.性能比较

 
数据规模 循环次数 Collections.sort耗时(微妙) TreeSet耗时(微妙)
1000000 10 339332微秒 1215165微秒
100000 10 24547微秒 49862微秒
10000 10 3246微秒 3884微秒
1000 10 752微秒 1097微秒

测试机器:windows、2.2GHz、Core i5、8G

2.测试代码

package com.google.common.base;

import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
import org.junit.Test;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;


public class SortTest {
    public static final int DEFAULT_ARRAY_LENGTH = 10 * 1000 * 1000;

    private List<Integer> createList(int arrLength) {
        List<Integer> numbers = Lists.newArrayList();
        for(int i = 0; i < DEFAULT_ARRAY_LENGTH; i++) {
            numbers.add(i);
        }
        Collections.shuffle(numbers);
        return numbers;
    }
    public long testCollectionsSort(List<Integer> numbers) {
        Ticker ticker = Ticker.systemTicker();
        long startTime = ticker.read();
        Collections.sort(numbers, new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                return Ints.compare(o2, o1);
            }
        });
        //long endTime = ticker.read();
        //System.out.println("[testCollectionsSort]" + (endTime - startTime) / 1000);
        //System.out.println("[testCollectionsSort]" + numbers.toString());
        return (ticker.read() - startTime) / 1000;
    }

    public long testSortedMap(List<Integer> numbers) {
        Ticker ticker = Ticker.systemTicker();
        long startTime = ticker.read();
        TreeSet<Integer> sortedNumberSet = new TreeSet<Integer>(new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                return Ints.compare(o2, o1);
            }
        });
        sortedNumberSet.addAll(numbers);
        //long endTime = ticker.read();
        //System.out.println("[testSortedMap]" + (endTime - startTime) / 1000);
        //List<Integer> newNumbers = Lists.newArrayList(sortedNumberSet);
        //System.out.println("[testSortedMap]" + newNumbers.toString());
        return (ticker.read() - startTime) / 1000;
    }

    @Test
    public void testSortMethodCompare() {
        int loopCount = 10;
        long collectionsSortTimeTotalCount = 0;
        long sortedMapTimeTotalCount = 0;
        List<Integer> numbers = createList(DEFAULT_ARRAY_LENGTH);
        for(int i = 0; i < loopCount; i ++) {
            List<Integer> tempNumbers = Lists.newArrayList(numbers);//每次循环使用同样数据
            sortedMapTimeTotalCount += testSortedMap(tempNumbers);//不会改变tempNumbers
            collectionsSortTimeTotalCount += testCollectionsSort(tempNumbers);
        }
        long collectionsSortTimeCount = collectionsSortTimeTotalCount / loopCount;
        long sortedMapTimeCount = sortedMapTimeTotalCount / loopCount;
        System.out.println("[testSortMethodCompare] loopCount = " + loopCount
                + ",listSize = " + DEFAULT_ARRAY_LENGTH);
        System.out.println("[CollectinSort]" + collectionsSortTimeCount + "微秒");
        System.out.println("[SortedMapSort]" + sortedMapTimeCount + "微秒");
    }
}

3.性能差异分析

a.TreeSet每次搜索要插入的位置时耗费的时间为log(n),n代表的是当前集合的长度,n从1增加至排序的数据集合list的list.size(),这个相比Collections.sort直接对整个数据集合进行排序具有优势。

b.TreeSet一个明显的劣势排序的过程是插入新节点的过程,创建新节点,插入新节点应该也会耗费一定的时间。

c.TreeSet另一个明显的劣势为由于其底层实现为红黑树,所以每次插入后需要对原有的集合进行修改以使得新集合底层仍然是红黑树。

以上是TreeSet实现排序的优势和劣势,由性能比较数据可以看出,相比TreeSet实现排序的优势,其劣势更明显。

posted @ 2017-11-07 12:49  shawWey  阅读(772)  评论(0编辑  收藏  举报