code: @NonNull
    public <K1 extends K, V1 extends V> LoadingCache<K1, V1> build(
        @NonNull CacheLoader<? super K1, V1> loader) {
      requireWeightWithWeigher();
  
      @SuppressWarnings("unchecked")
      Caffeine<K1, V1> self = (Caffeine<K1, V1>) this;
      return isBounded() || refreshes()
          ? new BoundedLocalCache.BoundedLocalLoadingCache<>(self, loader)
          : new UnboundedLocalCache.UnboundedLocalLoadingCache<>(self, loader);
    }
docs: Builds a cache, which either returns an already-loaded value for a given key or atomically
  computes or retrieves it using the supplied {@code CacheLoader}. If another thread is currently
  loading the value for this key, simply waits for that thread to finish and returns its loaded
  value. Note that multiple threads can concurrently load values for distinct keys.
  <p>
  This method does not alter the state of this {@code Caffeine} instance, so it can be invoked
  again to create multiple independent caches.
  
  @param loader the cache loader used to obtain new values
  @param <K1> the key type of the loader
  @param <V1> the value type of the loader
  @return a cache having the requested features