Преобразовать объект кеша в HashMap - PullRequest
0 голосов
/ 05 марта 2019

У меня есть класс кеша памяти, который я использую для хранения объектов Product и количества проданных предметов.

public class MemoryCache<K, V> {

    private long timeToLive;
    private LRUMap lruMap;

    /**
     * custom class that stores the cache value
     * and the timestamp for the last access
     */
    protected class CacheObject {

        public long lastAccessed = System.currentTimeMillis();
        public V value;

        protected CacheObject(V value) {
            this.value = value;
        }
    }

    /**
     * @param timeToLive    this is the permitted period of time for an object to live since
     *                      they are last accessed.
     *
     *                      <p>
     * @param timerInterval For the expiration of items use the timestamp of the last access
     *                      and in a separate thread remove the items when the time to live
     *                      limit is reached. This is nice for reducing memory pressure for
     *                      applications that have long idle time in between accessing the
     *                      cached objects. We have disabled the cleanup for this case scenario
     *
     *                      <p>
     * @param maxItems      Cache will keep most recently used items if we will try to add more
     *                      items then max specified. The Apache common collections have an LRUMap,
     *                      which, removes the least used entries from a fixed size map
     */
    public MemoryCache(long timeToLive, final long timerInterval, int maxItems) {

        this.timeToLive = timeToLive * 1000;

        lruMap = new LRUMap(maxItems);

        if (this.timeToLive > 0 && timerInterval > 0) {

            Thread t = new Thread(new Runnable() {

                public void run() {

                    while (true) {
                        try {
                            Thread.sleep(timerInterval * 1000);
                        } catch (InterruptedException ex) {
                        }

                        /*
                         * clean the objects from the cache that has reached
                         * the timeToLive period after the last access.
                         * */
                        cleanup();
                    }
                }
            });

            t.setDaemon(true);
            t.start();
        }
    }


    /**
     * insert a new key and value inside the cache memory
     *
     * @param key
     * @param value
     */
    public void put(K key, V value) {

        synchronized (lruMap) {

            if (key == null) {
                return;
            }

            /**
             * we have reached the max. size of items decided for the cache
             * and hence, we are not allowed to add more items for now. We
             * will need for the cache cleaning to add further items.
             */
            if (lruMap.isFull()) {
                return;
            }

            lruMap.put(key, new CacheObject(value));
        }
    }


    /**
     * retrieve the cache object from the memory using the key
     *
     * @param key
     * @return
     */
    @SuppressWarnings("unchecked")
    public V get(K key) {

        synchronized (lruMap) {

            MapIterator iterator = lruMap.mapIterator();

            K k = null;
            V v = null;

            CacheObject o = null;

            while (iterator.hasNext()) {

                k = (K) iterator.next();
                v = (V) iterator.getValue();

                Product product = (Product) k;
                Product product1 = (Product) key;

                if (product.getProductId().equalsIgnoreCase(product1.getProductId())) {
                    o = (CacheObject) v;
                }
            }

            if (o == null) {
                return null;
            } else {
                o.lastAccessed = System.currentTimeMillis();
                return o.value;
            }
        }
    }

    /**
     * remove a cache object from the memory using the key
     *
     * @param key
     */
    public void remove(K key) {

        synchronized (lruMap) {
            lruMap.remove(key);
        }
    }

    /**
     * find the size of the memory cache
     *
     * @return size of the cache
     */
    public int size() {

        synchronized (lruMap) {
            return lruMap.size();
        }
    }


    /**
     * we will look after the cache objects with a certain time interval
     * that has stayed in the memory inactively more than the time to live
     * period and remove them iteratively.
     */
    @SuppressWarnings("unchecked")
    public void cleanup() {

        long now = System.currentTimeMillis();
        ArrayList<K> deleteKey = null;

        synchronized (lruMap) {

            MapIterator iterator = lruMap.mapIterator();

            deleteKey = new ArrayList<K>((lruMap.size() / 2) + 1);

            K key = null;
            CacheObject object = null;

            while (iterator.hasNext()) {

                key = (K) iterator.next();
                object = (CacheObject) iterator.getValue();

                if (object != null && (now > (object.lastAccessed + timeToLive))) {
                    deleteKey.add(key);
                }
            }
        }

        for (K key : deleteKey) {

            synchronized (lruMap) {
                lruMap.remove(key);
            }

            Thread.yield();
        }
    }

    /**
     * convert the cache full of items to regular HashMap with the same
     * key and value pair
     *
     * @return
     */
    public Map<Product, Integer> convertToMap() {

        synchronized (lruMap) {

            Map<Product, Integer> map = new HashMap<>();
            MapIterator iterator = lruMap.mapIterator();

            K k = null;
            V v = null;

            CacheObject o = null;

            while (iterator.hasNext()) {

                k = (K) iterator.next();
                v = (V) iterator.getValue();

                Product product = (Product) k;

                // this fails right here
                int value = Integer.parseInt(String.valueOf(v));

                map.put(product, value);
            }

            return map;
        }
    }

}

Внутри класса API он представлен как

MemoryCache<Product, Integer> cache = new MemoryCache<>(1800, 500, 10000); 

. Я храню данные о товарах, которые продаются в классе API,

cache.put(product, 0);

Класс продукта, определенный ниже,

@Entity
public class Product {

    @Id
    @Column(name = "productId")
    private String productId;

    @Column(name = "stockId")
    private String id;

    @Column(name = "stock_timestamp")
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "UTC")
    private Timestamp timestamp;

    @Column(name = "quantity")
    private int quantity;


    public Product() {
    }

    public Product(String productId, Timestamp requestTimestamp, String id, Timestamp timestamp, int quantity) {
        this.productId = productId;
        this.id = id;
        this.timestamp = timestamp;
        this.quantity = quantity;
    }


   // getter, setter 

   // equals and hasCode 

   // toString
}

Метод convertToMap в классе MemoryCache берет хранилища кэшей и превращает их в HashMap.В методе есть ошибка в строке, где я пытаюсь сохранить int в качестве значения.

int value = Integer.parseInt(String.valueOf(v));

У меня есть скриншот для сеанса отладки.

enter image description here

Как видите, мне нужно получить значения (то есть 1000, 100) и указать их как value предполагаемого HashMap.Как правильно написать метод convertToMap для этой цели?

Ответы [ 2 ]

2 голосов
/ 06 марта 2019

Обобщения разработаны таким образом, чтобы избегать приведений и, следовательно, сделать код более надежным, но ваш способ использования обобщения в некоторой степени побеждает его.
Ваша проблема это прекрасно иллюстрирует:

MapIterator iterator = lruMap.mapIterator(); // no type associated to the iterator
// ....
k = (K) iterator.next(); // unsafe conversion
v = (V) iterator.getValue();    // unsafe conversion
Product product = (Product) k; // unsafe conversion    
// this fails right here
int value = Integer.parseInt(String.valueOf(v)); // how to be sure that v is an Integer ?

LRUMap и MapIterator, которые, вероятно, являются пользовательскими классами должны быть универсальными классами, которые опираются аналогично MemoryCache<K,V>, чтобы сделать все это согласованным.
Таким же образом этот метод указан в универсальном классеявно злоупотребление печатанием карты.Вы переходите от общих типов, объявленных в классе, к Product и Integer:

public class MemoryCache<K, V> {
    //..
    public Map<Product, Integer> convertToMap() {}
    //..
}

Наконец, ваш MemoryCache предназначен для работы только с Product и Integer как K, V тип бетона.В этом случае генерики бесполезны, вы должны удалить их.
Если позже вы захотите / хотите получить более универсальное решение, перейдите дальше в универсальном приложении, и вы должны закончить с convertToMap(), определенным как:

public Map<K, V> convertToMap() {...}
1 голос
/ 05 марта 2019

Как видите, ключ LruMap имеет тип Product, но значение имеет тип MemoryCache$CacheObject, а не Integer.

Поэтому вам нужно изменить код на

int value = Integer.parseInt(String.valueOf(v.value)); //Assuming v is of type MemoryCache$CacheObject

Или вы даже можете использовать это

Integer value = (Integer) v.value; 
...