@Override
  public void batch(List<? extends Row> actions, Object[] results) throws IOException {
    if (ArrayUtils.isEmpty(results)) {
      FutureUtils.get(table.batchAll(actions));
      return;
    }
    List<ThrowableWithExtraContext> errors = new ArrayList<>();
    List<CompletableFuture<Object>> futures = table.batch(actions);
    for (int i = 0, n = results.length; i < n; i++) {
      try {
        results[i] = FutureUtils.get(futures.get(i));
      } catch (IOException e) {
        results[i] = e;
        errors.add(new ThrowableWithExtraContext(e, EnvironmentEdgeManager.currentTime(),
          "Error when processing " + actions.get(i)));
      }
    }
    if (!errors.isEmpty()) {
      throw new RetriesExhaustedException(errors.size(), errors);
    }
  }
The table implementation based on {@link AsyncTable}.
hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableOverAsyncTable.java