Reputation: 101
Option 1:
List<Object> listObjects = new ArrayList<>();
for(Object object : listObjects){
object.setValue1("new value");
}
Option 2:
List<Object> listObjects = new ArrayList<>();
for(Object object : listObjects){
if(!object.getValue1().equals("new value"))
object.setValue1("new value");
}
Which of the above options is more performant in terms of cpu and memory usage?
Additional context: Let's imagine the objects list is pretty big and we loop through it every 5 seconds.
Upvotes: 1
Views: 136
Reputation:
Here is the test I did (openJDK 11). As I suspected,
String
, results will differ in scenarios above based on how equals is implemented.The "second time" case is relevant based you what you wrote:
Additional context: Let's imagine the objects list is pretty big and we loop through it every 5 seconds.
So, in general I do agree with advice in comments - worry about performance when you need to. Personally for me, the time is every time I finish the module and have unit tests, do performance testing. It takes day (or even less if you have automation), but I have never found it to be counter productive.
Output:
testSetValueNoCheck: 39.9644
testSetValueWithCheckUsingStatic: 40.4051
testSetValueWithCheckUsingStatic second time: 13.7888
testSetValueWithCheckUsingLiteral: 33.6455
testSetValueWithCheckUsingLiteral second time: 18.5136
Code:
class SetValueTest {
class MyObject {
private String _val;
MyObject(final String val) {
_val = val;
}
String getValue() {
return _val;
}
void setValue(final String val) {
_val = val;
}
}
ArrayList<MyObject> getData() {
final ArrayList<MyObject> data = new ArrayList<>();
for(int i = 0; i < 1000000; ++i) {
data.add(new MyObject(String.format("%d", i)));
}
return data;
}
SetValueTest() throws InterruptedException {
long start = 0L, end = 0L;
final ArrayList<MyObject> data1 = getData();
start = System.nanoTime();
testSetValueNoCheck(data1);
end = System.nanoTime();
System.out.println("testSetValueNoCheck: " + (end - start) / 1e6);
final ArrayList<MyObject> data2 = getData();
Thread.currentThread().sleep(1000);
start = System.nanoTime();
testSetValueWithCheckUsingStatic(data2);
end = System.nanoTime();
System.out.println("testSetValueWithCheckUsingStatic: " + (end - start) / 1e6);
start = System.nanoTime();
testSetValueWithCheckUsingStatic(data2);
end = System.nanoTime();
System.out.println("testSetValueWithCheckUsingStatic second time: " + (end - start) / 1e6);
final ArrayList<MyObject> data3 = getData();
Thread.currentThread().sleep(1000);
start = System.nanoTime();
testSetValueWithCheckUsingLiteral(data3);
end = System.nanoTime();
System.out.println("testSetValueWithCheckUsingLiteral: " + (end - start) / 1e6);
start = System.nanoTime();
testSetValueWithCheckUsingLiteral(data3);
end = System.nanoTime();
System.out.println("testSetValueWithCheckUsingLiteral second time: " + (end - start) / 1e6);
}
void testSetValueNoCheck(List<MyObject> objs) {
for (MyObject obj : objs) {
obj.setValue(NewValue);
}
}
void testSetValueWithCheckUsingLiteral(List<MyObject> objs) {
for (MyObject obj : objs) {
if (!obj.getValue().equals("new Value")) {
obj.setValue("new Value");
}
}
}
static final String NewValue = "new Value";
void testSetValueWithCheckUsingStatic(List<MyObject> objs) {
for (MyObject obj : objs) {
if (!obj.getValue().equals(NewValue)) {
obj.setValue(NewValue);
}
}
}
}
SECOND ROUND
--- changed the class so that and ran once per class run so that garbage collection\memory would not interfere with readings
--- sleep changed to 5 seconds to simulate actual scenario
--- ran each test 10 times with average as following:
testSetValueWithCheckUsingStatic: Average First Time: 27.728210 Second Time: 10.979410
testSetValueWithCheckUsingLiteral: Average First Time: 23.161670 Second Time: 12.896330
testSetValueNoCheckStatic: Average First Time: 20.294100 Second Time: 21.679260
testSetValueNoCheckLiteral: Average First Time: 29.137620 Second Time: 19.812040
static class SetValueTest {
class MyObject {
private String _val;
MyObject(final String val) {
_val = val;
}
String getValue() {
return _val;
}
void setValue(final String val) {
_val = val;
}
}
ArrayList<MyObject> getData() {
final ArrayList<MyObject> data = new ArrayList<>();
for(int i = 0; i < 1000000; ++i) {
data.add(new MyObject(String.format("%d", i)));
}
return data;
}
private final static int SleepTime = 5000;
private static final String NewValue = "new Value";
SetValueTest(final int test) throws InterruptedException {
final ArrayList<Double> firstTimes = new ArrayList<>();
final ArrayList<Double> secondTimes = new ArrayList<>();
String testName = "";
final int times = 10;
for (int i = 0; i < times; ++i) {
double firstTime = 0, secondTime = 0;
final ArrayList<MyObject> data = getData();
switch (test) {
case 1:
testName = "testSetValueWithCheckUsingStatic";
firstTime = testSetValueWithCheckUsingStatic(data);
secondTime = testSetValueWithCheckUsingStatic(data);
break;
case 2:
testName = "testSetValueWithCheckUsingLiteral";
firstTime = testSetValueWithCheckUsingLiteral(data);
secondTime = testSetValueWithCheckUsingLiteral(data);
break;
case 3:
testName = "testSetValueNoCheckStatic";
firstTime = testSetValueNoCheckStatic(data);
secondTime = testSetValueNoCheckStatic(data);
break;
case 4:
testName = "testSetValueNoCheckLiteral";
firstTime = testSetValueNoCheckLiteral(data);
secondTime = testSetValueNoCheckLiteral(data);
break;
}
firstTimes.add(firstTime);
secondTimes.add(secondTime);
}
double firstTimeTotal = 0, secondTimeTotal = 0;
System.out.println("Test: " + testName);
for (int time = 0; time < times; ++time) {
System.out.println(String.format("First Time: %f Second Time: %f", firstTimes.get(time), secondTimes.get(time)));
firstTimeTotal += firstTimes.get(time);
secondTimeTotal += secondTimes.get(time);
}
System.out.println(String.format("Average First Time: %f Second Time: %f", firstTimeTotal / times, secondTimeTotal / times));
}
double toMilliseconds(final long start, final long end) {
return ((end - start) / 1e6);
}
double testSetValueNoCheckStatic(List<MyObject> objs) throws InterruptedException {
long start = 0L, end = 0L;
start = System.nanoTime();
for (MyObject obj : objs) {
obj.setValue(NewValue);
}
end = System.nanoTime();
Thread.currentThread().sleep(SleepTime);
return toMilliseconds(start, end);
}
double testSetValueNoCheckLiteral(List<MyObject> objs) throws InterruptedException {
long start = 0L, end = 0L;
start = System.nanoTime();
for (MyObject obj : objs) {
obj.setValue("new Value");
}
end = System.nanoTime();
Thread.currentThread().sleep(SleepTime);
return toMilliseconds(start, end);
}
double testSetValueWithCheckUsingLiteral(List<MyObject> objs) throws InterruptedException {
long start = 0L, end = 0L;
start = System.nanoTime();
for (MyObject obj : objs) {
if (!obj.getValue().equals("new Value")) {
obj.setValue("new Value");
}
}
end = System.nanoTime();
Thread.currentThread().sleep(SleepTime);
return toMilliseconds(start, end);
}
double testSetValueWithCheckUsingStatic(List<MyObject> objs) throws InterruptedException {
long start = 0L, end = 0L;
start = System.nanoTime();
for (MyObject obj : objs) {
if (!obj.getValue().equals(NewValue)) {
obj.setValue(NewValue);
}
}
end = System.nanoTime();
Thread.currentThread().sleep(SleepTime);
return toMilliseconds(start, end);
}
}
Actual output:
Test: testSetValueWithCheckUsingStatic First Time: 42.110700 Second Time: 21.398500 First Time: 37.834800 Second Time: 10.124700 First Time: 18.263600 Second Time: 8.967400 First Time: 16.655500 Second Time: 7.146000 First Time: 18.729900 Second Time: 8.753300 First Time: 17.513100 Second Time: 14.622800 First Time: 24.000300 Second Time: 9.534700 First Time: 61.357000 Second Time: 11.677700 First Time: 26.832500 Second Time: 10.160400 First Time: 13.984700 Second Time: 7.408600 Average First Time: 27.728210 Second Time: 10.979410
Test: testSetValueWithCheckUsingLiteral First Time: 54.417700 Second Time: 22.161600 First Time: 20.950000 Second Time: 14.621500 First Time: 31.008100 Second Time: 13.631600 First Time: 14.052500 Second Time: 10.490900 First Time: 20.904800 Second Time: 8.727700 First Time: 13.338300 Second Time: 13.519100 First Time: 18.740800 Second Time: 13.030500 First Time: 14.959100 Second Time: 15.166100 First Time: 25.593000 Second Time: 8.041300 First Time: 17.652400 Second Time: 9.573000 Average First Time: 23.161670 Second Time: 12.896330
Test: testSetValueNoCheckStatic First Time: 34.467700 Second Time: 33.953200 First Time: 15.307500 Second Time: 14.245300 First Time: 34.042700 Second Time: 31.824600 First Time: 11.989300 Second Time: 12.266800 First Time: 15.556500 Second Time: 24.501000 First Time: 12.314800 Second Time: 16.539600 First Time: 14.333300 Second Time: 14.500300 First Time: 11.876900 Second Time: 21.599900 First Time: 39.020400 Second Time: 31.754800 First Time: 14.031900 Second Time: 15.607100 Average First Time: 20.294100 Second Time: 21.679260
Test: testSetValueNoCheckLiteral First Time: 49.325300 Second Time: 27.528700 First Time: 26.355500 Second Time: 27.800100 First Time: 23.862700 Second Time: 15.576400 First Time: 25.133000 Second Time: 16.290500 First Time: 28.379000 Second Time: 18.192400 First Time: 83.170600 Second Time: 18.183800 First Time: 13.570100 Second Time: 14.341100 First Time: 11.793900 Second Time: 13.960000 First Time: 16.238900 Second Time: 30.233200 First Time: 13.547200 Second Time: 16.014200 Average First Time: 29.137620 Second Time: 19.812040
Upvotes: 1
Reputation: 1242
My vote would be option 1: it's shorter (ignoring the setValue2 call) and if it's an object, the assignment is just loading and storing a pointer, whereas the equal
comparison could take a long time if the object is very big.
Upvotes: 1