guava/src/com/google/common/collect/Tables.java
public static <T, R, C, V, I extends Table<R, C, V>> Collector<T, ?, I> toTable(
      java.util.function.Function<? super T, ? extends R> rowFunction,
      java.util.function.Function<? super T, ? extends C> columnFunction,
      java.util.function.Function<? super T, ? extends V> valueFunction,
      BinaryOperator<V> mergeFunction,
      java.util.function.Supplier<I> tableSupplier) {
    checkNotNull(rowFunction);
    checkNotNull(columnFunction);
    checkNotNull(valueFunction);
    checkNotNull(mergeFunction);
    checkNotNull(tableSupplier);
    return Collector.of(
        tableSupplier,
        (table, input) ->
            merge(
                table,
                rowFunction.apply(input),
                columnFunction.apply(input),
                valueFunction.apply(input),
                mergeFunction),
        (table1, table2) -> {
          for (Table.Cell<R, C, V> cell2 : table2.cellSet()) {
            merge(table1, cell2.getRowKey(), cell2.getColumnKey(), cell2.getValue(), mergeFunction);
          }
          return table1;
        });
  }
public static <T, R, C, V, I extends Table<R, C, V>> Collector<T, ?, I> toTable(
      java.util.function.Function<? super T, ? extends R> rowFunction,
      java.util.function.Function<? super T, ? extends C> columnFunction,
      java.util.function.Function<? super T, ? extends V> valueFunction,
      BinaryOperator<V> mergeFunction,
      java.util.function.Supplier<I> tableSupplier) {
    checkNotNull(rowFunction);
    checkNotNull(columnFunction);
    checkNotNull(valueFunction);
    checkNotNull(mergeFunction);
    checkNotNull(tableSupplier);
    return Collector.of(
        tableSupplier,
        (table, input) ->
            merge(
                table,
                rowFunction.apply(input),
                columnFunction.apply(input),
                valueFunction.apply(input),
                mergeFunction),
        (table1, table2) -> {
          for (Table.Cell<R, C, V> cell2 : table2.cellSet()) {
            merge(table1, cell2.getRowKey(), cell2.getColumnKey(), cell2.getValue(), mergeFunction);
          }
          return table1;
        });
  }
Returns a {@link Collector} that accumulates elements into a {@code Table} created using the
specified supplier, whose cells are generated by applying the provided mapping functions to the
input elements. Cells are inserted into the generated {@code Table} in encounter order.

<p>If multiple input elements map to the same row and column, the specified merging function is
used to combine the values. Like {@link
java.util.stream.Collectors#toMap(java.util.function.Function, java.util.function.Function,
BinaryOperator, java.util.function.Supplier)}, this Collector throws a {@code
NullPointerException} on null values returned from {@code valueFunction}, and treats nulls
returned from {@code mergeFunction} as removals of that row/column pair.

@since 21.0