我需要预先填充一个包含大量整数值的List。
除了迭代之外,还有更快的方法吗?
当前代码:
class VlanManager {
Queue<Integer> queue = Lists.newLinkedList();
public VlanManager(){
for (int i = 1; i < 4094; i++) {
queue.add(i);
}
}
此代码位于经常创建的类的构造函数中,因此我希望这样做尽可能高效(读取:性能不是代码行)
答案 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做很多事情。
话虽如此,有许多可行的方法可以更有效地实现这一目标。但它们取决于您的具体使用模式。仅举几例:
boolean [] inUse' and set the taken vlan-id to
如果已采用,则为当然还有更多......
所有这些方法都要求您建立自己的队列&#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 );
}
}