初始化大型整数列表的最快方法是什么?

时间:2014-07-19 23:02:22

标签: java

我需要预先填充一个包含大量整数值的List。

除了迭代之外,还有更快的方法吗?

当前代码:

class VlanManager {
    Queue<Integer> queue = Lists.newLinkedList();

    public VlanManager(){
    for (int i = 1; i < 4094; i++) {
        queue.add(i);
    }
}

此代码位于经常创建的类的构造函数中,因此我希望这样做尽可能高效(读取:性能不是代码行)

3 个答案:

答案 0 :(得分:4)

4094不是很多要循环的项目,但如果它经常被调用,你可能会看一下用静态变量做什么。

private static Integer[] theList;

static {
    theList = new Integer[4094];
    for (int i = 1; i < 4094; i++) {
        theList[i-1] = i;
    }
}

然后将该列表设为List

Queue<Integer> intQue = new LinkedList(Arrays.asList(theList));

如果您有可变对象列表,则存在使用此方法的危险。下面是可能发生的事情的一个例子。 整数是不可变的,所以这实际上并不适用于你的问题

class MyMutableObject {
    public int theValue;
}

class Test {

    private static MyMutableObject[] theList;

    static {
        theList = new MyMutableObject[4094];
        for (int i = 1; i <= 4094; i++) {
            theList[i-1] = new MyMutableObject();
            theList[i-1].theValue = i;
        }
    }

    public static void main(String [] args) {
        Queue<MyMutableObject> que = new LinkedList(Arrays.asList(theList));
        System.out.println(que.peek().theValue); // 1
        // your actually modifing the same object as the one in your static list
        que.peek().theValue = -100; 
        Queue<MyMutableObject> que2 = new LinkedList(Arrays.asList(theList));
        System.out.println(que2.peek().theValue); // -100
    }
}

@Bohemian在使用静态List而不是数组方面有一些好处,而性能提升非常小,性能提升也是如此。另外因为'array'实际上只被用作List而不是数组,所以它应该被声明为。

private static List<Integer> theList;

static {
    theList = new ArrayList(4094);
    for (Integer i = 0; i < 4094; i++) {
        theList.add(i+1);
    }
}

答案 1 :(得分:3)

最快的方法是创建一个引用列表(使用实例块初始化 - 在一个语句中整齐地包装它):

private static final List<Integer> LIST = new ArrayList<Integer>(4094) {{
    for (int i = 1; i < 4094; i++)
       LIST.add(i);
}};

然后在构造函数中,使用复制构造函数初始化队列:

Queue<Integer> queue;

public VlanManager(){
    queue = new LinkedList<Integer>(LIST);
}

您不会编写比JDK更快的实现。

答案 2 :(得分:1)

我意识到这个问题已经得到了回答。但我认为缺少一个重要的答案:使用值0..4093初始化LinkedList的最快方法是.. DON&#39; T DO IT ALL AT 。特别是如果速度是一个问题。

你基本上要做的是创建一个由4093个Node元素组成的结构,每个元素由两个指向prev / next元素的指针和一个指向Integer对象的指针组成。必须创建({和1}}每个Node。此外,几乎每个包含的Integer都必须创建(并释放)。 &#39;近&#39;因为Java使用整数缓存但通常(您可以使用系统属性更改它)在-127..127范围内。

为了获得一个简单的整数列表,这是很多事情,如果使用密集,那么事后可以为GC做很多事情。

话虽如此,有许多可行的方法可以更有效地实现这一目标。但它们取决于您的具体使用模式。仅举几例:

  1. 使用数组:boolean [] inUse' and set the taken vlan-id to如果已采用,则为
  2. 更好的是使用BitSet而不是数组
  3. 不要存储哪个vlan是免费的,但是要使用哪个vlan。我认为他们往往是自由的,因此有更多的自由,因为有被采取的。 (这意味着要少跟踪)。
  4. 如果您坚持使用LinkedList,请不要在课堂上对其进行初始化,但已将其初始化。这取决于你需要多少。你可以保留他们的池子。或许您的代码允许重新使用旧列表。 (是的,您可以在使用后对它们进行排序。)
  5. 当然还有更多......

    所有这些方法都要求您建立自己的队列&#39;接口。但也许这并不像Java那样丰富。这真的不难。如果你真的使用它,你可以达到性能提升因子10x-1000x ++。

    使用BitSet并且实例化成本几乎为零的可能实现可能是:

    import java.util.BitSet;
    
    import org.testng.annotations.Test;
    
    
    public class BitSetQueue {
    
        // Represents the values 0..size-1
        private final BitSet bitset;
        private final int size;
        private int current = 0;
        private int taken = 0;
    
        public BitSetQueue( int size ){
    
            this.bitset = new BitSet( size );
            this.size = size;
            this.current = size-1;
        }
    
        public int poll(){
    
            // prevent endless loop
            if( taken == size ) return -1;
    
            // seek for next free value.
            // can be changed according to policy
            while( true ){
    
                current = (current+1)%size;
    
                if( ! bitset.get( current ) ){
                    bitset.set( current );
                    taken++;
                    return current;
                }
            }
        }
    
        public boolean free( int num ){
    
            if( bitset.get( num ) ){
                bitset.clear( num );
                taken--;
                return true;
            }
            return false;
        }
    
    
        @Test
        public static void usage(){
    
            BitSetQueue q = new BitSetQueue( 4094 );
    
            for( int i = 0; i < 4094; i++ ){
                assertEquals( q.poll(), i );
            }
            assertEquals( q.poll(), -1 ); // No more available
    
            assertTrue( q.free( 20 ) );
            assertTrue( q.free( 51 ) );
    
            assertEquals( q.poll(), 20 );
            assertEquals( q.poll(), 51 );
        }
    
    }