

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 在 適用於 Java 的 AWS SDK 2.x 中使用分頁結果
<a name="pagination"></a>

當回應物件太大而無法在單一回應中傳回時，許多 AWS 操作會傳回分頁結果。在 適用於 Java 的 AWS SDK 1.0 中，回應包含您用來擷取下一頁結果的字符。相反地， 適用於 Java 的 AWS SDK 2.x 具有自動調色方法，可進行多個服務呼叫，自動為您取得下一頁的結果。您只需編寫處理結果的程式碼即可。自動化適用於同步和非同步用戶端。

**注意**  
這些程式碼片段假設您了解[使用 SDK 的基本概念](using.md)，並已使用[單一登入存取](get-started-auth.md#setup-credentials)來設定您的環境。

## 同步分頁
<a name="synchronous-pagination"></a>

下列範例示範同步分頁方法來列出 Amazon S3 儲存貯體中的物件。

### 逐一查看頁面
<a name="iterate-pages"></a>

第一個範例示範如何使用`listRes`分頁器物件、[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/paginators/ListObjectsV2Iterable.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/paginators/ListObjectsV2Iterable.html)執行個體，透過 `stream`方法逐一查看所有回應頁面。程式碼會在回應頁面上串流，將回應串流轉換為`[S3Object](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/model/S3Object.html)`內容串流，然後處理 Amazon S3 物件的內容。

下列匯入適用於此同步分頁區段中的所有範例。

#### 匯入
<a name="synchronous-pagination-ex-import"></a>

```
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Random;

import software.amazon.awssdk.core.waiters.WaiterResponse;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.paginators.ListObjectsV2Iterable;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.model.S3Exception;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Response;
import software.amazon.awssdk.services.s3.model.S3Object;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
import software.amazon.awssdk.services.s3.model.DeleteBucketRequest;
import software.amazon.awssdk.services.s3.model.CreateMultipartUploadRequest;
import software.amazon.awssdk.services.s3.model.CreateMultipartUploadResponse;
import software.amazon.awssdk.services.s3.model.CompletedMultipartUpload;
import software.amazon.awssdk.services.s3.model.CreateBucketRequest;
import software.amazon.awssdk.services.s3.model.CompletedPart;
import software.amazon.awssdk.services.s3.model.CreateBucketConfiguration;
import software.amazon.awssdk.services.s3.model.UploadPartRequest;
import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadRequest;
import software.amazon.awssdk.services.s3.waiters.S3Waiter;
import software.amazon.awssdk.services.s3.model.HeadBucketRequest;
import software.amazon.awssdk.services.s3.model.HeadBucketResponse;
```

```
        ListObjectsV2Request listReq = ListObjectsV2Request.builder()
            .bucket(bucketName)
            .maxKeys(1)
            .build();

        ListObjectsV2Iterable listRes = s3.listObjectsV2Paginator(listReq);
        // Process response pages
        listRes.stream()
            .flatMap(r -> r.contents().stream())
            .forEach(content -> System.out
                .println(" Key: " + content.key() + " size = " + content.size()));
```

請參閱 GitHub 上的[完整範例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/s3/src/main/java/com/example/s3/S3ObjectOperations.java#L112)。

### 反覆運算物件
<a name="iterate-objects"></a>

以下範例示範如何逐一查看回應傳回的物件，而非回應的頁面。`ListObjectsV2Iterable` 類別`contents`方法會傳回 [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html)，提供數種方法來處理基礎內容元素。

#### 使用串流
<a name="use-a-stream"></a>

下列程式碼片段會在回應內容上使用 `stream`方法，以逐一查看分頁項目集合。

```
        // Helper method to work with paginated collection of items directly.
        listRes.contents().stream()
            .forEach(content -> System.out
                .println(" Key: " + content.key() + " size = " + content.size()));
```

請參閱 GitHub 上的[完整範例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/s3/src/main/java/com/example/s3/S3ObjectOperations.java#L127)。

#### 使用 for-each 迴圈
<a name="for-loop"></a>

由於 `SdkIterable`擴展了`Iterable`界面，因此您可以像任何 一樣處理內容`Iterable`。下列程式碼片段使用標準`for-each`迴圈逐一查看回應的內容。

```
        for (S3Object content : listRes.contents()) {
            System.out.println(" Key: " + content.key() + " size = " + content.size());
        }
```

請參閱 GitHub 上的[完整範例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/s3/src/main/java/com/example/s3/S3ObjectOperations.java#L133)。

### 手動分頁
<a name="manual-pagination"></a>

如果您的使用案例有需要，也可以使用手動分頁。使用回應物件中的下一個符記以進行後續請求。下列範例使用`while`迴圈。

```
        ListObjectsV2Request listObjectsReqManual = ListObjectsV2Request.builder()
            .bucket(bucketName)
            .maxKeys(1)
            .build();

        boolean done = false;
        while (!done) {
            ListObjectsV2Response listObjResponse = s3.listObjectsV2(listObjectsReqManual);
            for (S3Object content : listObjResponse.contents()) {
                System.out.println(content.key());
            }

            if (listObjResponse.nextContinuationToken() == null) {
                done = true;
            }

            listObjectsReqManual = listObjectsReqManual.toBuilder()
                .continuationToken(listObjResponse.nextContinuationToken())
                .build();
        }
```

請參閱 GitHub 上的[完整範例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/s3/src/main/java/com/example/s3/S3ObjectOperations.java#L90)。

## 非同步分頁
<a name="asynchronous-pagination"></a>

下列範例示範列出 DynamoDB 資料表的非同步分頁方法。

### 反覆查看資料表名稱的頁面
<a name="iterate-pages-async"></a>

下列兩個範例使用非同步 DynamoDB 用戶端，呼叫 `listTablesPaginator`方法並請求取得 [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/paginators/ListTablesPublisher.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/paginators/ListTablesPublisher.html)。 `ListTablesPublisher`實作兩個界面，提供許多處理回應的選項。我們會查看每個界面的方法。

#### 使用 `Subscriber`
<a name="use-a-subscriber"></a>

下列程式碼範例示範如何使用 實作的`org.reactivestreams.Publisher`界面來處理分頁結果`ListTablesPublisher`。若要進一步了解被動串流模型，請參閱[被動串流 GitHub 儲存庫](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.2/README.md)。

下列匯入適用於此非同步分頁區段中的所有範例。

##### 匯入
<a name="use-a-subscriber-ex-imports"></a>

```
import io.reactivex.rxjava3.core.Flowable;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import reactor.core.publisher.Flux;
import software.amazon.awssdk.core.async.SdkPublisher;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.dynamodb.model.ListTablesRequest;
import software.amazon.awssdk.services.dynamodb.model.ListTablesResponse;
import software.amazon.awssdk.services.dynamodb.paginators.ListTablesPublisher;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
```

下列程式碼會取得`ListTablesPublisher`執行個體。

```
        // Creates a default client with credentials and region loaded from the
        // environment.
        final DynamoDbAsyncClient asyncClient = DynamoDbAsyncClient.create();

        ListTablesRequest listTablesRequest = ListTablesRequest.builder().limit(3).build();
        ListTablesPublisher publisher = asyncClient.listTablesPaginator(listTablesRequest);
```

下列程式碼使用 的匿名實作`org.reactivestreams.Subscriber`來處理每個頁面的結果。

`onSubscribe` 方法會呼叫 `Subscription.request` 方法以啟動向發佈者請求資料。必須呼叫這個方法，才能開始從發佈者取得資料。

訂閱者`onNext`的方法透過存取所有資料表名稱並列印每個資料表名稱來處理回應頁面。處理頁面後，會向發佈者請求另一個頁面。此方法會重複呼叫，直到擷取所有頁面為止。

如果擷取資料時發生錯誤，會觸發 `onError` 方法。最後，所有頁面都已請求完，會呼叫 `onComplete` 方法。

```
        // A Subscription represents a one-to-one life-cycle of a Subscriber subscribing
        // to a Publisher.
        publisher.subscribe(new Subscriber<ListTablesResponse>() {
            // Maintain a reference to the subscription object, which is required to request
            // data from the publisher.
            private Subscription subscription;

            @Override
            public void onSubscribe(Subscription s) {
                subscription = s;
                // Request method should be called to demand data. Here we request a single
                // page.
                subscription.request(1);
            }

            @Override
            public void onNext(ListTablesResponse response) {
                response.tableNames().forEach(System.out::println);
                // After you process the current page, call the request method to signal that
                // you are ready for next page.
                subscription.request(1);
            }

            @Override
            public void onError(Throwable t) {
                // Called when an error has occurred while processing the requests.
            }

            @Override
            public void onComplete() {
                // This indicates all the results are delivered and there are no more pages
                // left.
            }
        });
```

請參閱 GitHub 上的[完整範例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/AsyncPagination.java#L83)。

#### 使用 `Consumer`
<a name="id1pagination"></a>

`ListTablesPublisher` 實作 的`SdkPublisher`界面具有採用 `Consumer`並傳回 `subscribe`的方法`CompletableFuture<Void>`。

來自此界面的 `subscribe`方法可用於簡單的使用案例，當 `org.reactivestreams.Subscriber`可能過多的額外負荷時。由於以下程式碼會耗用每個頁面，因此會呼叫每個頁面上的 `tableNames`方法。`tableNames` 方法會傳回使用 `forEach`方法處理的 `java.util.List` DynamoDB 資料表名稱的 。

```
        // Use a Consumer for simple use cases.
        CompletableFuture<Void> future = publisher.subscribe(
                response -> response.tableNames()
                        .forEach(System.out::println));
```

請參閱 GitHub 上的[完整範例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/AsyncPagination.java#L96)。

### 反覆運算資料表名稱
<a name="iterate-objects-async"></a>

以下範例示範如何逐一查看回應傳回的物件，而非回應的頁面。類似於先前與其 `contents`方法一起顯示的同步 Amazon S3 範例，DynamoDB 非同步結果類別`ListTablesPublisher`具有與基礎項目集合互動的`tableNames`便利方法。`tableNames` 方法的傳回類型是 [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html)，可用於跨所有頁面請求項目。

#### 使用 `Subscriber`
<a name="id2"></a>

下列程式碼會取得資料表名稱`SdkPublisher`基礎集合的 。

```
        // Create a default client with credentials and region loaded from the
        // environment.
        final DynamoDbAsyncClient asyncClient = DynamoDbAsyncClient.create();

        ListTablesRequest listTablesRequest = ListTablesRequest.builder().limit(3).build();
        ListTablesPublisher listTablesPublisher = asyncClient.listTablesPaginator(listTablesRequest);
        SdkPublisher<String> publisher = listTablesPublisher.tableNames();
```

下列程式碼使用 的匿名實作`org.reactivestreams.Subscriber`來處理每個頁面的結果。

訂閱者`onNext`的方法會處理集合的個別元素。在這種情況下，它是資料表名稱。處理資料表名稱之後，會向發佈者請求另一個資料表名稱。此方法會重複呼叫，直到擷取所有資料表名稱為止。

```
        // Use a Subscriber.
        publisher.subscribe(new Subscriber<String>() {
            private Subscription subscription;

            @Override
            public void onSubscribe(Subscription s) {
                subscription = s;
                subscription.request(1);
            }

            @Override
            public void onNext(String tableName) {
                System.out.println(tableName);
                subscription.request(1);
            }

            @Override
            public void onError(Throwable t) {
            }

            @Override
            public void onComplete() {
            }
        });
```

請參閱 GitHub 上的[完整範例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/AsyncPagination.java#L147)。

#### 使用 `Consumer`
<a name="for-loop-async"></a>

下列範例使用 的 `subscribe`方法`SdkPublisher`，需要 `Consumer`來處理每個項目。

```
        // Use a Consumer.
        CompletableFuture<Void> future = publisher.subscribe(System.out::println);
        future.get();
```

請參閱 GitHub 上的[完整範例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/AsyncPagination.java#L161)。

### 使用第三方程式庫
<a name="use-third-party-library"></a>

您可以使用其他第三方程式庫，而非實作自訂的訂閱者。此範例示範如何使用 RxJava，但可使用任何實作被動串流界面的程式庫。如需該程式庫的詳細資訊，請參閱 [ GitHub 上的 RxJava wiki 頁面](https://github.com/ReactiveX/RxJava/wiki)。

若要使用該程式庫，請將其新增做為相依性。如果使用 Maven，範例會顯示要使用的 POM 片段。

 **POM 項目** 

```
<dependency>
      <groupId>io.reactivex.rxjava3</groupId>
      <artifactId>rxjava</artifactId>
      <version>3.1.6</version>
</dependency>
```

 **Code** 

```
        DynamoDbAsyncClient asyncClient = DynamoDbAsyncClient.create();
        ListTablesPublisher publisher = asyncClient.listTablesPaginator(ListTablesRequest.builder()
                .build());

        // The Flowable class has many helper methods that work with
        // an implementation of an org.reactivestreams.Publisher.
        List<String> tables = Flowable.fromPublisher(publisher)
                .flatMapIterable(ListTablesResponse::tableNames)
                .toList()
                .blockingGet();
        System.out.println(tables);
```

請參閱 GitHub 上的[完整範例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/AsyncPagination.java#L198)。