每个新与空的最佳实践
Best practice foreach new vs null
我有一个方法可以每 5 秒迭代一次大数组。在每个循环中,我向 ArrayList
.
添加一些内容
我听说使用 new
需要更多的内存。
我需要知道 ArrayList
以上 empty/clear 的最佳方法是什么。
private ArrayList<MyMarker> myArray;
public void callEveryFiveSeconds(){
myArray = new ArrayList<MyMarker>(); //clears previous array data
//grab array data from server
for (int i = 0; i < 200; i++) {
myArray.add(someData);
}
}
或
private ArrayList<MyMarker> myArray = new ArrayList<MyMarker>();
public void callEveryFiveSeconds(){
myArray = null; //clears previous array data
//grab array data from server
for (int i = 0; i < 200; i++) {
myArray.add(someData);
}
}
第二个代码错误,会抛出NullPointerException。
如果你想清除列表:
public void callEveryFiveSeconds(){
myArray.clear();
//grab array data from server
for (int i = 0; i < 200; i++) {
myArray.add(someData);
}
}
至于哪个选项更好——创建一个新的 ArrayList
实例或清除现有的实例——后者应该占用更少的内存,因为它不必为新的 ArrayList
。前者会用一个新数组分配一个新的 ArrayList
,而旧的 ArrayList
将有资格进行垃圾回收。这意味着第二个选项(清除列表)将为垃圾收集器节省工作,这在性能方面也是一件好事。
如果每次调用 callEveryFiveSeconds
时添加到列表中的元素数量保持相似,则每次清除现有列表而不是创建新列表还有另一个好处。原因是新建ArrayList
不指定初始容量会创建一个初始容量较小的列表,如果向新列表添加很多元素,则需要多次调整大小,这也费时间。
有一个名为 clear() 的方法可以清空数组列表:
public void callEveryFiveSeconds(){
myArray.clear();
//grab array data from server
for (int i = 0; i < 200; i++) {
myArray.add(someData);
}
}
你在做什么叫做过早优化。如果您每 5 秒只调用一次方法,那么您应该正常编写代码,而不考虑微优化。如果您的程序 运行ning 在现代处理器上,那么它将能够在每次方法调用之间执行数百亿条指令。优化这一种方法不会对您的程序性能产生总体影响。记忆方面,您的数组列表似乎只有 200 个项目。在 64 位 OS 上,您的数组列表将需要不到 2kB 的空间来容纳所有需要的内存资源。当现代计算机有千兆字节的可用内存时,在宏伟的计划中也没有多少。
实际上,与创建新的 ArrayList
相比,使用 ArrayList.clear
可能会为您的程序创建更多的工作。这是因为通过清除 ArrayList
,程序必须将支持数组中的每个项目设置为 null
。然而,Java 的垃圾收集器非常高效,当它处理一个未使用的 ArrayList
时,它能够在不先清除它的情况下处理后备数组。
在我的计算机上给出以下微基准测试,每个 运行 一千万次:
public static final Object OBJ = new Object();
public static final int LENGTH = 200;
public static ArrayList<Object> clearArrayList(ArrayList<Object> objects) {
objects.clear();
for (int i = 0; i < LENGTH; i++) {
objects.add(OBJ);
}
return objects;
}
public static ArrayList<Object> newArrayList() {
ArrayList<Object> objects = new ArrayList<Object>(LENGTH);
for (int i = 0; i < LENGTH; i++) {
objects.add(OBJ);
}
return objects;
}
每次调用 newArrayList
的结果是 870 纳秒,每次调用 clearArrayList
的结果是 970 纳秒。所以你可以看到使用新的 ArrayList
稍微快一点,但还不够关心。特别是当您谈论每 5 秒 100 ns 的差异时。您会注意到我为新的 运行 预先调整了 ArrayList
的大小。当 ArrayList 未预先调整大小时,平均调用时间为 1690ns。虽然这长了 50%,但仍然不够关心,因为您没有充分调用此方法。
使用 new 时线程同步的好处
那么为什么要使用这两种方式呢?使用新的 ArrayList
有一个好处,那就是它可以更好地与线程同步。如果您重复使用同一个 ArrayList,那么您必须在更改 ArrayList 时阻止其他线程访问它。如果您使用新的 ArrayList
,那么您可以先私下创建新的 ArrayList
,然后再让其他线程访问它。
例如
private ArrayList<Object> objects = new ArrayList<Object>();
private final Object lock = new Object();
public ArrayList<Object> getObjects() {
synchronized(lock) {
return objects;
}
}
public void setObjects(ArrayList<Object> newObjects) {
synchronized(lock) {
objects = newObjects;
}
}
public void callEveryFiveSeconds() {
// note that this method does not explicitly use synchronisation.
// Synchronisation is only used when setting objects.
ArrayList<Object> newObjects = new ArrayList<Object>();
for (int i = 0; i < 200; i++) {
newObjects.add(new Object());
}
setObjects(newObjects);
}
我有一个方法可以每 5 秒迭代一次大数组。在每个循环中,我向 ArrayList
.
我听说使用 new
需要更多的内存。
我需要知道 ArrayList
以上 empty/clear 的最佳方法是什么。
private ArrayList<MyMarker> myArray;
public void callEveryFiveSeconds(){
myArray = new ArrayList<MyMarker>(); //clears previous array data
//grab array data from server
for (int i = 0; i < 200; i++) {
myArray.add(someData);
}
}
或
private ArrayList<MyMarker> myArray = new ArrayList<MyMarker>();
public void callEveryFiveSeconds(){
myArray = null; //clears previous array data
//grab array data from server
for (int i = 0; i < 200; i++) {
myArray.add(someData);
}
}
第二个代码错误,会抛出NullPointerException。
如果你想清除列表:
public void callEveryFiveSeconds(){
myArray.clear();
//grab array data from server
for (int i = 0; i < 200; i++) {
myArray.add(someData);
}
}
至于哪个选项更好——创建一个新的 ArrayList
实例或清除现有的实例——后者应该占用更少的内存,因为它不必为新的 ArrayList
。前者会用一个新数组分配一个新的 ArrayList
,而旧的 ArrayList
将有资格进行垃圾回收。这意味着第二个选项(清除列表)将为垃圾收集器节省工作,这在性能方面也是一件好事。
如果每次调用 callEveryFiveSeconds
时添加到列表中的元素数量保持相似,则每次清除现有列表而不是创建新列表还有另一个好处。原因是新建ArrayList
不指定初始容量会创建一个初始容量较小的列表,如果向新列表添加很多元素,则需要多次调整大小,这也费时间。
有一个名为 clear() 的方法可以清空数组列表:
public void callEveryFiveSeconds(){
myArray.clear();
//grab array data from server
for (int i = 0; i < 200; i++) {
myArray.add(someData);
}
}
你在做什么叫做过早优化。如果您每 5 秒只调用一次方法,那么您应该正常编写代码,而不考虑微优化。如果您的程序 运行ning 在现代处理器上,那么它将能够在每次方法调用之间执行数百亿条指令。优化这一种方法不会对您的程序性能产生总体影响。记忆方面,您的数组列表似乎只有 200 个项目。在 64 位 OS 上,您的数组列表将需要不到 2kB 的空间来容纳所有需要的内存资源。当现代计算机有千兆字节的可用内存时,在宏伟的计划中也没有多少。
实际上,与创建新的 ArrayList
相比,使用 ArrayList.clear
可能会为您的程序创建更多的工作。这是因为通过清除 ArrayList
,程序必须将支持数组中的每个项目设置为 null
。然而,Java 的垃圾收集器非常高效,当它处理一个未使用的 ArrayList
时,它能够在不先清除它的情况下处理后备数组。
在我的计算机上给出以下微基准测试,每个 运行 一千万次:
public static final Object OBJ = new Object();
public static final int LENGTH = 200;
public static ArrayList<Object> clearArrayList(ArrayList<Object> objects) {
objects.clear();
for (int i = 0; i < LENGTH; i++) {
objects.add(OBJ);
}
return objects;
}
public static ArrayList<Object> newArrayList() {
ArrayList<Object> objects = new ArrayList<Object>(LENGTH);
for (int i = 0; i < LENGTH; i++) {
objects.add(OBJ);
}
return objects;
}
每次调用 newArrayList
的结果是 870 纳秒,每次调用 clearArrayList
的结果是 970 纳秒。所以你可以看到使用新的 ArrayList
稍微快一点,但还不够关心。特别是当您谈论每 5 秒 100 ns 的差异时。您会注意到我为新的 运行 预先调整了 ArrayList
的大小。当 ArrayList 未预先调整大小时,平均调用时间为 1690ns。虽然这长了 50%,但仍然不够关心,因为您没有充分调用此方法。
使用 new 时线程同步的好处
那么为什么要使用这两种方式呢?使用新的 ArrayList
有一个好处,那就是它可以更好地与线程同步。如果您重复使用同一个 ArrayList,那么您必须在更改 ArrayList 时阻止其他线程访问它。如果您使用新的 ArrayList
,那么您可以先私下创建新的 ArrayList
,然后再让其他线程访问它。
例如
private ArrayList<Object> objects = new ArrayList<Object>();
private final Object lock = new Object();
public ArrayList<Object> getObjects() {
synchronized(lock) {
return objects;
}
}
public void setObjects(ArrayList<Object> newObjects) {
synchronized(lock) {
objects = newObjects;
}
}
public void callEveryFiveSeconds() {
// note that this method does not explicitly use synchronisation.
// Synchronisation is only used when setting objects.
ArrayList<Object> newObjects = new ArrayList<Object>();
for (int i = 0; i < 200; i++) {
newObjects.add(new Object());
}
setObjects(newObjects);
}