这篇文章整理两个可以直接复用的 Java 片段:获取国际电话区号,以及为不稳定的外部调用增加指数退避重试。

获取国家和地区的国际区号

Google libphonenumber 内置了电话号码元数据,可以从 ISO 3166-1 地区代码映射到国际区号。

Maven 依赖可以统一由项目的版本管理控制:

<dependency>
    <groupId>com.googlecode.libphonenumber</groupId>
    <artifactId>libphonenumber</artifactId>
    <version>${libphonenumber.version}</version>
</dependency>

保留地区与区号的对应关系

PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();

Map<String, Integer> regionToCallingCode = phoneUtil.getSupportedRegions()
        .stream()
        .sorted()
        .collect(Collectors.toMap(
                Function.identity(),
                phoneUtil::getCountryCodeForRegion,
                (left, right) -> left,
                LinkedHashMap::new
        ));

这里得到的是“地区代码 → 国际电话区号”,例如 CN → 86。它不是城市固定电话的国内区号。

只获取不重复的区号

多个地区可能共享同一个国际区号,因此只需要数字列表时应去重:

List<Integer> callingCodes = phoneUtil.getSupportedRegions()
        .stream()
        .map(phoneUtil::getCountryCodeForRegion)
        .distinct()
        .sorted()
        .collect(Collectors.toList());

电话号码规则会变化,应用应定期升级 libphonenumber 元数据,而不是把结果永久固化。

使用指数退避执行重试

指数退避会逐步拉长两次调用之间的等待时间,适用于短暂网络故障、服务限流或临时不可用。它不应掩盖参数错误、权限错误等不可恢复异常。

引入 guava-retrying

<dependency>
    <groupId>com.github.rholder</groupId>
    <artifactId>guava-retrying</artifactId>
    <version>2.0.0</version>
</dependency>

配置 Retryer

private final Retryer<Void> retryer = RetryerBuilder.<Void>newBuilder()
        .retryIfException()
        .withStopStrategy(StopStrategies.stopAfterAttempt(5))
        .withWaitStrategy(
                WaitStrategies.exponentialWait(1000, 32, TimeUnit.SECONDS)
        )
        .build();

这段配置最多执行 5 次(包含首次调用),等待时间按指数增长并封顶在 32 秒。具体等待序列由库内部的尝试次数计算决定,不要把它理解为固定定时任务。

执行业务调用

try {
    retryer.call(() -> {
        remoteClient.send();
        return null;
    });
} catch (RetryException e) {
    // 已达到停止条件
    throw new IllegalStateException("调用重试后仍然失败", e);
} catch (ExecutionException e) {
    // Callable 执行过程中出现无法继续处理的异常
    throw new IllegalStateException("调用执行失败", e.getCause());
}

生产使用建议

  • 不要无差别重试所有异常,应尽量限定为超时、连接重置、HTTP 429/503 等可恢复错误。
  • 对非幂等写操作增加幂等键,避免重试造成重复扣款或重复创建订单。
  • 指数退避最好叠加随机抖动,避免大量实例同时重试形成“惊群”。
  • 记录尝试次数、最终失败原因和总耗时,便于监控重试是否正在放大故障。