As Adrian Larson pointed out, object instantiation is pretty cheap.
One pattern that I've used in some places is to create a base instance outside of a loop, setting as many common fields as possible, and then clone the base instance inside the loop, setting specific fields only where required.
Task baseTask = new Task(
ActivityDate = Date.TODAY().addDays(3),
Prioity = 'High'
// ...other common fields here
);
Task cloneTask;
for (Case record : createdCases)
{
cloneTask = baseTask.clone(false, true, false, false);
cloneTask.whatId = record.Id;
tasks.add(cloneTask);
}
I've no idea how performant the sObject clone()
method is (I should probably benchmark that), but I do know for a fact that using object.field = value
is slower than setting fields via name/value pairs in the sObject constructor.
At any rate, this is unlikely to impact you unless you're attempting to get close to the 10,000 DML row limit per transaction.
+edit:
wrote up a benchmarking script
Decimal time1;
Decimal time2;
Integer iterations = 20000;
Decimal bareLoop;
Decimal instantiateInLoop;
Decimal cloneIntoList;
Decimal cloneInLoop;
Decimal cloneInLoopAndSet1Field;
Decimal cloneInLoopAndSet2Fields;
Decimal clone3Fields;
Decimal clone4Fields;
time1 = Limits.getCpuTime();
for(Integer i = 0; i < iterations; i++){
}
time2 = Limits.getCpuTime();
bareLoop = time2-time1;
List<Opportunity> testOppList = new List<Opportunity>();
time1 = Limits.getCpuTime();
for(Integer i = 0; i < iterations; i++){
testOppList.add(new Opportunity(
description = 'test description',
stageName = '1 - Working',
Amount = i,
CloseDate = Date.Today().addDays(3)
));
}
time2 = Limits.getCpuTime();
instantiateInLoop = time2-time1 - bareLoop;
testOppList.clear();
Opportunity baseInstance;
Opportunity cloneInstance;
time1 = Limits.getCpuTime();
baseInstance = new Opportunity(
description = 'test description',
stageName = '1 - Working',
CloseDate = Date.Today().addDays(3)
);
for(Integer i = 0; i < iterations; i++){
testOppList.add(baseInstance.clone(false, true, false, false));
}
time2 = Limits.getCpuTime();
cloneIntoList = time2-time1 - bareLoop;
testOppList.clear();
time1 = Limits.getCpuTime();
baseInstance = new Opportunity(
description = 'test description',
stageName = '1 - Working',
CloseDate = Date.Today().addDays(3)
);
for(Integer i = 0; i < iterations; i++){
cloneInstance = baseInstance.clone(false, true, false, false);
testOppList.add(cloneInstance);
}
time2 = Limits.getCpuTime();
cloneInLoop = time2-time1 - bareLoop;
testOppList.clear();
time1 = Limits.getCpuTime();
baseInstance = new Opportunity(
description = 'test description',
stageName = '1 - Working',
CloseDate = Date.Today().addDays(3)
);
for(Integer i = 0; i < iterations; i++){
cloneInstance = baseInstance.clone(false, true, false, false);
cloneInstance.Amount = i;
testOppList.add(cloneInstance);
}
time2 = Limits.getCpuTime();
cloneInLoopAndSet1Field = time2-time1 - bareLoop;
testOppList.clear();
time1 = Limits.getCpuTime();
baseInstance = new Opportunity(
description = 'test description',
stageName = '1 - Working',
CloseDate = Date.Today().addDays(3)
);
for(Integer i = 0; i < iterations; i++){
cloneInstance = baseInstance.clone(false, true, false, false);
cloneInstance.Amount = i;
cloneInstance.Name = 'Opp-' + i;
testOppList.add(cloneInstance);
}
time2 = Limits.getCpuTime();
cloneInLoopAndSet2Fields = time2-time1 - bareLoop;
testOppList.clear();
baseInstance = new Opportunity(
description = 'test description',
stageName = '1 - Working',
CloseDate = Date.Today().addDays(3)
);
time1 = Limits.getCpuTime();
for(Integer i = 0; i < iterations; i++){
testOppList.add(baseInstance.clone(false, true, false, false));
}
time2 = Limits.getCpuTime();
clone3Fields = time2-time1 - bareLoop;
testOppList.clear();
baseInstance = new Opportunity(
description = 'test description',
stageName = '1 - Working',
Amount = 100,
CloseDate = Date.Today().addDays(3)
);
time1 = Limits.getCpuTime();
for(Integer i = 0; i < iterations; i++){
testOppList.add(baseInstance.clone(false, true, false, false));
}
time2 = Limits.getCpuTime();
clone4Fields = time2-time1 - bareLoop;
testOppList.clear();
system.debug('Time taken in bare loop (just instantiating, comparing, and incrementing i): ' + bareLoop);
system.debug('Time taken directly adding new instance to list (minus bareLoop): ' + instantiateInLoop);
system.debug('Time taken cloning instance direcly into list (minus bareLoop): ' + cloneIntoList);
system.debug('Time taken cloning instance direcly into list, 3 fields (minus bareLoop): ' + clone3Fields);
system.debug('Time taken cloning instance direcly into list, 4 fields (minus bareLoop): ' + clone4Fields);
system.debug('Time taken cloning instance direcly into list, per record, 1 extra field (minus bareLoop): ' + ((clone4Fields - clone3Fields)/iterations));
system.debug('Time taken cloning, then adding instance to list (minus bareLoop): ' + cloneInLoop);
system.debug('Time taken cloning, setting 1 field, then adding instance to list (minus bareLoop): ' + cloneInLoopAndSet1Field);
system.debug('Time taken cloning, setting 2 fields, then adding instance to list (minus bareLoop): ' + cloneInLoopAndSet2Fields);
system.debug('Time taken (per record) to set 1 field using dot notation (minus bareLoop): ' + ((cloneInLoopAndSet1Field - cloneInLoop)/iterations));
system.debug('Time taken (per record) to set an additional field using dot notation (minus bareLoop): ' + ((cloneInLoopAndSet2Fields - cloneInLoopAndSet1Field)/iterations));
results (20,000 iterations, note that there will be some non-deterministic variance between runs):
Time taken in bare loop (just instantiating, comparing, and incrementing i): 11
Time taken directly adding new instance to list (minus bareLoop): 672
Time taken cloning instance direcly into list (minus bareLoop): 331
Time taken cloning instance direcly into list, 3 fields (minus bareLoop): 334
Time taken cloning instance direcly into list, 4 fields (minus bareLoop): 373
Time taken cloning instance direcly into list, per record, 1 extra field (minus bareLoop): 0.00195
Time taken cloning, then adding instance to list (minus bareLoop): 354
Time taken cloning, setting 1 field, then adding instance to list (minus bareLoop): 970
Time taken cloning, setting 2 fields, then adding instance to list (minus bareLoop): 1459
Time taken (per record) to set 1 field using dot notation (minus bareLoop): 0.0312
Time taken (per record) to set an additional field using dot notation (minus bareLoop): 0.02445
I did a separate test to see what the incremental cost was to an additional field being set in the constructor.
Cost per record per additional field instantiating in loop: 0.01655
Conclusions:
- Cloning is fast, roughly half the CPU cost of repeatedly making new instances and setting name/value pairs in the constructor (even when storing in a temp variable
- Cloning should always remain faster than repeated constructor calls, as the incremental cost for cloning an additional field is an order of magnitude (i.e. 10x) lower
- This benefit disappears as soon as you need to set even a single value on a record using dot-notation
- There appears to be no number of fields that you can set via constructor that would cause cloning + dot notation to be favorable (dot notation cost is ~2x that of setting an additional field in the constructor)