code: @NotNull
      public static <T, K, V, M extends Map<K, V>> Collector<T, ?, M> toMap(
              @NotNull final Function<? super T, ? extends K> keyMapper,
              @NotNull final Function<? super T, ? extends V> valueMapper,
              @NotNull final Supplier<M> mapFactory) {
          return new CollectorsImpl<T, M, M>(
  
                  mapFactory,
  
                  new BiConsumer<M, T>() {
                      @Override
                      public void accept(M map, T t) {
                          final K key = keyMapper.apply(t);
                          final V value = Objects.requireNonNull(valueMapper.apply(t));
  
                          // To avoid calling map.get to determine duplicate keys
                          // we check the result of map.put
                          final V oldValue = map.put(key, value);
                          if (oldValue != null) {
                              // If there is duplicate key, rollback previous put operation
                              map.put(key, oldValue);
                              throw duplicateKeyException(key, oldValue, value);
                          }
                      }
                  }
          );
      }
docs: Returns a {@code Collector} that fills new {@code Map} with input elements.
  
  If the mapped keys contain duplicates, an {@code IllegalStateException} is thrown.
  Use {@link #toMap(Function, Function, BinaryOperator, Supplier)} to handle merging of the values.
  
  @param <T> the type of the input elements
  @param <K> the result type of key mapping function
  @param <V> the result type of value mapping function
  @param <M> the type of the resulting {@code Map}
  @param keyMapper  a mapping function to produce keys
  @param valueMapper  a mapping function to produce values
  @param mapFactory  a supplier function that provides new {@code Map}
  @return a {@code Collector}
  @see #toMap(Function, Function, BinaryOperator, Supplier)