Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

do...while() using Java 8 stream?

I want to convert this java do...while() to a Java 8.

private static final Integer PAGE_SIZE = 200;
int offset = 0;

Page page = null;
do {
    // Get all items.
    page = apiService.get(selector);

    // Display items.
    if (page.getEntries() != null) {
    for (Item item : page.getEntries()) {
        System.out.printf("Item with name '%s' and ID %d was found.%n", item.getName(),
            item.getId());
    }
    } else {
    System.out.println("No items were found.");
    }

    offset += PAGE_SIZE;
    selector = builder.increaseOffsetBy(PAGE_SIZE).build();
} while (offset < page.getTotalNumEntries());

This code makes api call to apiService and retrieves data. Then, I want to loop until offset is less than totalNumberEntries.

What is prohibiting me from using while() or foreach with step or any other kind of loop loop is I don't know the totalNumberEntries without making API call (which is done inside the loop).

One option I can think of is making the API call just to get the totalNumberEntries and proceed with the loop.

like image 249
biniam Avatar asked Oct 21 '25 06:10

biniam


2 Answers

If you really want/need a stream api for retrieving pages, you could create your own streams by implementing a Spliterator to retrieve each page in its tryAdvance() method.

It would look something like this

public class PageSpliterator implements Spliterator<Page> {
    private static final Integer PAGE_SIZE = 200;

    int offset;
    ApiService apiService;
    int selector;
    Builder builder;
    Page page;

    public PageSpliterator(ApiService apiService) {
      // initialize Builder?
    }

    @Override
    public boolean tryAdvance(Consumer<? super Page> action) {
    if (page == null || offset < page.getTotalNumEntries()) {
        Objects.requireNonNull(action);
        page = apiService.get(selector);
        action.accept(page);
        offset += PAGE_SIZE;
        selector = builder.increaseOffsetBy(PAGE_SIZE).build();
        return true;
    } else {
        // Maybe close/cleanup apiService?
        return false;
    }
    }

    @Override
    public Spliterator<Page> trySplit() {
    return null; // can't split
    }

    @Override
    public long estimateSize() {
    return Long.MAX_VALUE; // don't know in advance
    }

    @Override
    public int characteristics() {
    return IMMUTABLE; // return appropriate
    }
}

Then you could use the it like this:

StreamSupport.stream(new PageSpliterator(apiService), false)
  .flatMap(page -> page.getEntries()
  .stream())
  .forEach(item -> System.out.printf("Item with name '%s' and ID %d was found.%n", item.getName(), item.getId()));
like image 160
rogerkl Avatar answered Oct 22 '25 19:10

rogerkl


In my opinion there are not many scenarios where a do...while loop would be the best choice. This however is such a scenario.

Just because there is new stuff in Java8, does not mean you have to use it. If you still want to implement it with a foreach loop, for whatever reason, then I would go for the option you mentioned. Do the API call at the beginning and then start the foreach.

like image 25
BT9 Avatar answered Oct 22 '25 21:10

BT9



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!