2016-04-21 12 views
0

Ich will das Java konvertieren do ... while() zu einem Java 8.do ... while() mit Java 8 Stream?

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()); 

Dieser Code api Aufruf apiService macht und ruft Daten. Dann möchte ich Schleife, bis der Offset weniger als totalNumberEntries ist.

Was aus verbietet mir while() oder foreach with step oder any other kind of loop Schleife ist, weiß ich nicht die totalNumberEntries ohne API-Aufruf zu machen (die innerhalb der Schleife erfolgt).

Eine Option, die ich mir vorstellen kann, besteht darin, den API-Aufruf zu machen, nur um die totalNumberEntries zu erhalten und mit der Schleife fortzufahren.

+8

'do {...} while (...)' vollkommen legal ist in Java 8. –

+1

Bitte teilen Sie, was Sie ausprobiert haben – sidgate

+2

Technisch wäre der funktionale Weg ein 'takeWhile', der in Java existiert. 9 http://stackoverflow.com/a/32304570/1743880 – Tunaki

Antwort

1

Meiner Meinung nach gibt es nicht viele Szenarien, in denen eine do ... while-Schleife die beste Wahl wäre. Dies ist jedoch ein solches Szenario.

Nur weil es in Java8 neue Sachen gibt, heißt das nicht, dass Sie es benutzen müssen. Wenn Sie es trotzdem aus irgendeinem Grund mit einer foreach-Schleife implementieren möchten, dann würde ich für die Option gehen, die Sie erwähnten. Rufen Sie die API am Anfang auf und starten Sie dann die Foreach.

2

Wenn Sie wirklich eine Stream-API zum Abrufen von Seiten benötigen/benötigen, können Sie eigene Streams erstellen, indem Sie einen Spliterator implementieren, um jede Seite in ihrer tryAdvance() -Methode abzurufen.

Es wäre so etwas wie dieses aussehen

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 
    } 
} 

Dann könnten Sie die es wie folgt verwendet werden:

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()));