Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Caching using Supplier Java 8

This method, as I know, memorizes (caches) the value of supplier that passed as the parameter. As I understand It behaves like singleton pattern. Can anyone explain how it works?

  public static <T> Supplier<T> memoize(final Supplier<? extends T> valueSupplier)
  {
    final List<T> memoryList= new ArrayList<>();
    return () -> {
      if (memoryList.isEmpty()) {
        memoryList.add(valueSupplier.get());
      }
      return memoryList.get(0);
    };
  }

Usage like this:

Supplier<SomeClass> cachedValue = memoize(() -> someClassObject.getSomeValueToBeCached());
cachedValue.get().doMethod();
like image 304
memor1s Avatar asked May 25 '17 09:05

memor1s


People also ask

What does Suppliers Memoize do?

Suppliers. memoize is a simple method that takes a Supplier and returns a new Supplier that caches the value returned from the supplied Supplier. get() method. This convenient helper allows us to turn any Supplier into a lazily loaded cached value.

Is caching Memoized?

Memoization is a specific form of caching that involves caching the return value of a function based on its parameters. Caching is a more general term; for example, HTTP caching is caching but not memoization.

What is a supplier in Java?

In Java 8, Supplier is a simple functional interface, which is represents an operator that provides a value for each call. Supplier has only one get() method and has no default method. Java Functional Interface.

What is caching in Java example?

The Java Object Cache provides caching for expensive or frequently used Java objects when the application servers use a Java program to supply their content. Cached Java objects can contain generated pages or can provide support objects within the program to assist in creating new content.


2 Answers

Ok, so let's rewrite the code in small steps towards more old-style, verbose Java. Maybe that makes it simpler to understand.

First step: get rid of the lambda:

public static <T> Supplier<T> memoize(final Supplier<? extends T> valueSupplier)
{
    final List<T> memoryList= new ArrayList<>();
    return new Supplier<T>() {
        @Override
        public T get() {
            if (memoryList.isEmpty()) {
                memoryList.add(valueSupplier.get());
            }
            return memoryList.get(0);
        }
    };
}

Next step: extract the anonymous inner class into a standalone class. While the anonymous class had access to the local variables of its containing method (memoryList), a "normal" class has not, so we're moving the list into the caching supplier.

class CachingSupplier<T> implements Supplier<T> {

    final List<T> memoryList= new ArrayList<>();
    private Supplier<T> originalSupplier;

    public CachingSupplier(Supplier<T> originalSupplier) {
        this.originalSupplier = originalSupplier;
    }

    @Override
    public T get() {
        if (memoryList.isEmpty()) {
            memoryList.add(originalSupplier.get());
        }
        return memoryList.get(0);
    }
}

public static <T> Supplier<T> memoize(final Supplier<? extends T> valueSupplier) {
  return new CachingSupplier<>(valueSupplier);
}

Finally, let's replace the ArrayList by a simple reference.

class CachingSupplier<T> implements Supplier<T> {

    private T cachedValue;
    private Supplier<T> originalSupplier;

    public CachingSupplier(Supplier<T> originalSupplier) {
        this.originalSupplier = originalSupplier;
    }

    @Override
    public T get() {
        if (cachedValue == null) {
            cachedValue = originalSupplier.get();
        }
        return cachedValue;
    }
}

public static <T> Supplier<T> memoize(final Supplier<? extends T> valueSupplier) {
  return new CachingSupplier<>(valueSupplier);
}

Maybe that's easier to understand. If you are still unclear about something, just ask in a comment and I'll try to explain it.

like image 176
Rolf Schäuble Avatar answered Oct 12 '22 14:10

Rolf Schäuble


How about this?

public static <T> Supplier<T> memoize(final Supplier<? extends T> factory) {
    final List<T> cache = new ArrayList<>();
    return () -> {
               // v--- check the value is cached?
        if (cache.isEmpty()) {
                           // v--- return the value created by factory
            cache.add(factory.get());
               // ^--- adding the value into the cache
        }
        return cache.get(0); 
                  // ^--- return the cached value
    };
}

Usage

Supplier<String> factory = ()-> new String("foo"); 

assert factory.get() == factory.get(); // return false;
assert memoize(factory).get() == memoize(factory).get(); //return false;

                 // v--- storing the memoized factory for using as further
Supplier<String> memoized = memoize(original);
assert memoized.get() == memoized.get(); // return true.
                    // ^--- they are the same.  
like image 25
holi-java Avatar answered Oct 12 '22 12:10

holi-java