The overall answer to this is that there is an Apex Batch Handler which controls batch class execution. You could think of it like a method that calls your start method, then launches threads which call your execute method and handles the result of those threads, and finally calls your finish method once all execute threads have completed. With this in mind:
The handler mentioned may be implemented something like:
Batchable<Account> myBatch = batchFromBatchExecuteCall; Iterator<Account> queryResult = myBatch.start().iterator(); while(queryResult.hasNext()) { List<Account> scope = new List<Account>{queryResult.next()}; for(integer i = 1; i < scopeSize && queryResult.hasNext(); ++i) { scope.add(queryResult.next()); } launchThread(myBatch.execute, scope); }Of course, the above is very simplified to what the handler likely actually has to do, but this should demonstrate how it can take an iterator and use it to execute scopes
Both
ListandqueryLocatoralready implement theiterable()interface, so the caller can just use theiterablemethod whether it gets back one of those types or a customIterabletype.
How do you create a Custom Iterator in Apex?
What is the difference between Database.QueryLocator and Iterator/Iterable in Batch Apex?
What are the limitations of using Iterators in Batch Apex?
Try this one for the constructor and below sample code it should work:
public class MyIterable implements Iterable<String> {
private List<String> strings;
public MyIterable(List<String> strings) {
this.strings = strings;
}
public Iterator<String> iterator() {
return strings.iterator();
}
}
In case you need Test Class:
@IsTest
public class MyIterableTest {
@IsTest
static void testIterableForLoop() {
List<String> strings = new List<String>{'Hello', 'World'};
MyIterable iterable = new MyIterable(strings);
for (String str : iterable) {
System.debug(str);
}
}
}
I ran the test in Setup > Application Test Execution instead of Dev Console .
My test runs in Dev Console did not appear in the Application Test Execution, that was the telltale sign.
I also had a Test start and stop, I'm not sure if that helped. Below are the classes I used
Class:
public class MyIterable implements Iterable<String> {
private List<String> strings;
public MyIterable(List<String> strings){
this.strings = strings;
}
public Iterator<String> iterator() {
return strings.iterator();
}
}
Test Class:
@IsTest
public class MyIterableTest {
@IsTest
static void testIterableForLoop() {
List<String> strings = new List<String>{'Hello', 'World'};
MyIterable iterable = new MyIterable(strings);
// Test execution
Test.startTest();
for (String str : new MyIterable(strings) ) {
System.debug(str);
}
Test.stopTest();
}
}
You are returning a new instance of your iterator() every single time your while statement is called. It is simply restarting every time it is called. Try:
List<string> listX = new List<String> {'A','B','C'};
Iterator<String> iter = listX.iterator();
while(iter.hasNext())
system.debug(iter.next());
The above code just grabs a single instance of your Iterator object and allows you to process the values.
List<String> baby = new List<String> {'aman','Anu','Anurag','Akshu'};
List<String> Action = new List <String> {'crying','sleeping','burping','playing'};
Iterator <String> babyIterator = baby.iterator();
Iterator <String>actIterator = Action.iterator();
while(babyIterator.hasNext() && actIterator.hasNext())
{
String babyItem = babyIterator.next();
String ActionItem = actIterator.next();
system.debug(babyItem + ActionItem);
}
always provide same argument or data collection type provided in "<>"to the Iterator so it will work.