Azure SDK for Java 中的分页和迭代

本文概述如何使用 Azure SDK for Java 的分页和迭代功能,有效且高效地处理大型数据集。

Azure Java SDK 中的客户端库提供的许多操作都会返回多个结果。 在这些情况下,Azure Java SDK 定义了一组可接受的返回类型,以确保通过一致性最大限度地改善开发人员体验。 同步 API 使用的返回类型是 PagedIterable,而异步 API 使用的是 PagedFlux。 由于用例不同,API 也略有不同,但它们在概念方面具有相同的要求:

  • 可以轻松地分别循环访问集合中的每个元素,而无需手动分页或跟踪延续令牌。 PagedIterablePagedFlux 通过循环访问反序列化为给定类型 T 的分页响应,让此任务变得简单。 PagedIterable 实现 Iterable 接口,并提供 API 用于接收 Stream,而 PagedFlux 提供 Flux。 在所有情况下,分页操作都是透明的,并且迭代在仍有结果循环访问的情况下继续运行。

  • 实现逐页显式循环访问。 这样做可以让你更清楚地了解何时发出请求,并能够访问每页的响应信息。 PagedIterablePagedFlux 都具有可返回相应类型以按页(而不是按单个元素)循环访问的方法。

本文分别介绍 Java Azure SDK 同步 API 和异步 API。 当你使用同步客户端时,你将看到同步迭代 API;当你使用异步客户端时,你将看到异步迭代 API。

同步分页和迭代

本部分介绍同步 API。

循环访问单个元素

如上所述,最常见的用例是分别循环访问每个元素,而不是按页循环访问。 以下代码示例演示如何通过 PagedIterable API 使用你偏好的迭代样式来实现此功能。

使用 for-each 循环

因为 PagedIterable 实现 Iterable,所以你可循环访问元素,如以下示例所示:

PagedIterable<Secret> secrets = client.listSecrets();
for (Secret secret : secrets) {
   System.out.println("Secret is: " + secret);
}

使用 Stream

因为 PagedIterable 上定义了 stream() 方法,所以你可调用它来使用标准 Java Stream API,如以下示例所示:

client.listSecrets()
      .stream()
      .forEach(secret -> System.out.println("Secret is: " + secret));

使用迭代器

因为 PagedIterable 实现 Iterable,所以它还具有用于实现 Java 迭代器编程样式的 iterator() 方法,如以下示例所示:

Iterator<Secret> secrets = client.listSecrets().iterator();
while (it.hasNext()) {
   System.out.println("Secret is: " + it.next());
}

循环访问 页

处理单个页时,可循环访问每个页,例如,在需要 HTTP 响应信息时,或在延续令牌对于保留迭代历史记录很重要时。 不管是按页还是按每个项进行循环访问,性能以及对服务发出的调用数量没有任何差别。 基础实现按需加载下一页,只要取消订阅 PagedFlux,就不会进一步调用服务。

使用 for-each 循环

调用 listSecrets() 时,你将获得 PagedIterable,它具有 iterableByPage() API。 此 API 生成 Iterable<PagedResponse<Secret>> 而不是 Iterable<Secret>PagedResponse 提供响应元数据以及对延续令牌的访问权限,如以下示例所示:

Iterable<PagedResponse<Secret>> secretPages = client.listSecrets().iterableByPage();
for (PagedResponse<Secret> page : secretPages) {
   System.out.println("Response code: " + page.getStatusCode());
   System.out.println("Continuation Token: " + page.getContinuationToken());
   page.getElements().forEach(secret -> System.out.println("Secret value: " + secret))
}

还有一个接受延续令牌的 iterableByPage 重载。 如果之后想要返回到同一迭代点,则可调用此重载。

使用 Stream

以下示例演示 streamByPage() 方法如何执行上述操作。 此 API 还具有延续令牌重载,用于之后返回到同一迭代点。

client.listSecrets()
      .streamByPage()
      .forEach(page -> {
          System.out.println("Response code: " + page.getStatusCode());
          System.out.println("Continuation Token: " + page.getContinuationToken());
          page.getElements().forEach(secret -> System.out.println("Secret value: " + secret))
      });

异步观察页和单个元素

本部分介绍异步 API。 在异步 API 中,网络调用发生在其他线程中,而不是在调用 subscribe() 的主线程中。 这意味着主线程可能会在结果出来之前终止。 你需要确保在异步操作完成之前,应用程序不会退出。

观察单个元素

以下示例演示如何通过 PagedFlux API 来异步观察单个元素。 可通过多种方法订阅 Flux 类型。 有关详细信息,请参阅 Reactor 3 Reference Guide(Reactor 3 参考指南)中的 Simple Ways to Create a Flux or Mono and Subscribe to It(创建 Flux 或 Mono 并订阅的简单方法)。 此示例是具有三个 lambda 表达式的一种情况,这三个表达式分别用于使用者、错误使用者和完成使用者。 同时拥有这三项是不错的做法,但在某些情况下,只需拥有使用者,还可能需要错误使用者。

asyncClient.listSecrets()
   .subscribe(secret -> System.out.println("Secret value: " + secret),
       ex -> System.out.println("Error listing secrets: " + ex.getMessage()),
       () -> System.out.println("Successfully listed all secrets"));

观察页

以下示例演示 PagedFlux API 如何通过使用 byPage() API 并提供使用者、错误使用者和完成使用者,让你以异步方式观察每个页面。

asyncClient.listSecrets().byPage()
  .subscribe(page -> {
          System.out.println("Response code: " + page.getStatusCode());
          System.out.println("Continuation Token: " + page.getContinuationToken());
          page.getElements().forEach(secret -> System.out.println("Secret value: " + secret))
      },
      ex -> System.out.println("Error listing pages with secret: " + ex.getMessage()),
      () -> System.out.println("Successfully listed all pages with secret"));

后续步骤

现在,你已熟悉 Azure SDK for Java 中的分页和迭代,接下来请考虑查看 Azure SDK for Java 中的长期操作。 与大多数常见的 HTTP 请求相比,长期操作的运行时间更长,这通常是因为它们需要在服务器端执行一些操作。