簡體   English   中英

在構造函數中設置Java Collection的大小更好嗎?

[英]Is it better to set size of a Java Collection in constructor?

如果我知道當時的大小,最好將Collection的大小傳遞給Collection構造函數嗎? 在擴展Collection和分配/重新分配方面的節省效果是否顯着?

如果我知道Collection最小大小但不知道上限,該怎么辦。 至少以最小的尺寸創建它仍然值得嗎?

不同的集合對此有不同的性能影響,對於ArrayList而言,節省是非常明顯的。

import java.util.*;
public class Main{
public static void main(String[] args){
  List<Integer> numbers = new ArrayList<Integer>(5);
  int max = 1000000;
  // Warmup
  for (int i=0;i<max;i++) {
    numbers.add(i);
  }

  long start = System.currentTimeMillis();
  numbers = new ArrayList<Integer>(max);
  for (int i=0;i<max;i++) {
    numbers.add(i);
  }
  System.out.println("Preall: "+(System.currentTimeMillis()-start));

  start = System.currentTimeMillis();
  numbers = new ArrayList<Integer>(5);
  for (int i=0;i<max;i++) {
    numbers.add(i);
  }
  System.out.println("Resizing: "+(System.currentTimeMillis()-start));

}
}

結果:

Preall: 26
Resizing: 58

如果將max設置為10000000的值的10倍,則得出:

Preall: 510
Resizing: 935

因此,即使大小不同,您也可以看到比率保持不變。

這幾乎是最壞的測試,但是一次填充一個元素一個數組很常見,您會發現速度大約相差2倍。

所有集合都是自動擴展的。 不知道邊界不會影響其功能(直到遇到其他問題,例如使用所有可用內存等),但是可能會影響其性能。

有一些收藏。 最值得注意的是ArrayList,因為要復制整個基礎數組,所以自動擴展的成本很高。 數組列表的默認大小為10,每次達到最大值時,其大小都會增加一倍。 因此,假設您知道您的arraylist將包含110個對象,但不指定其大小,則將發生以下復制

復制10-> 20
復制20-> 40
復制40-> 80
復制80-> 160

通過預先告訴arraylist它包含110個項目,您可以跳過這些副本。

有根據的猜測總比沒有好

即使您錯了也沒關系。 集合仍將自動展開,並且您仍將避免某些副本。 降低性能的唯一方法是,如果您的猜測太大了:這將導致分配給集合的內存過多

好,這是我的jmh代碼:

@OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 3, time = 1)
@Measurement(iterations = 3, time = 1)
@Fork(3)
public class Comparison
{
  static final int size = 1_000;
  @GenerateMicroBenchmark
  public List<?> testSpecifiedSize() {
    final ArrayList<Integer> l = new ArrayList(size);
    for (int i = 0; i < size; i++) l.add(1);
    return l;
  }

  @GenerateMicroBenchmark
  public List<?> testDefaultSize() {
    final ArrayList<Integer> l = new ArrayList();
    for (int i = 0; i < size; i++) l.add(1);
    return l;
  }
}

我的size = 10_000結果:

Benchmark             Mode Thr    Cnt  Sec         Mean   Mean error    Units
testDefaultSize       avgt   1      9    1       80.770        2.095  usec/op
testSpecifiedSize     avgt   1      9    1       50.060        1.078  usec/op

size = 1_000結果:

Benchmark             Mode Thr    Cnt  Sec         Mean   Mean error    Units
testDefaultSize       avgt   1      9    1        6.208        0.131  usec/op
testSpecifiedSize     avgt   1      9    1        4.900        0.078  usec/op

我的解釋:

  • presizing對默認大小一些邊緣;
  • 邊緣不是那么壯觀;
  • 花在添加到列表上的絕對時間是微不足道的。

我的結論是:

如果增加初始大小,則可以使您的心臟感到溫暖,但客觀地說,客戶不太可能注意到差異。

在少數情況下,大小是眾所周知的(例如,當將已知數量的元素填充到新集合中時),出於性能原因可以進行設置。

通常,最好省略它,而改用默認構造函數,這樣可以使代碼更簡單和更好理解。

對於基於數組的集合,重新調整大小是一項非常昂貴的操作。 這就是為什么為ArrayList傳遞准確大小是一個好主意的原因。

如果將大小設置為最小大小( MIN ),然后將MIN +1個元素添加到集合中,則需要重新調整大小。 ArrayList()調用ArrayList(10)因此如果MIN足夠大,那么您將獲得一些好處。 但是最好的方法是使用期望的集合大小創建ArrayList

但是可能您更喜歡LinkedList,因為它沒有添加元素的任何開銷(盡管list.get(i)開銷為O(i))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM