#java #collections #apache-commons
#java #Коллекции #apache-commons
Вопрос:
Я ожидал, что org.apache.commons.collections4.map.PassiveExpiringMap будет работать из коробки. К сожалению, это не работает для меня в наиболее очевидном случае использования истекающих объектов вовремя. Приведенный ниже код создает политику истечения срока действия в 5 секунд. Тест ожидает 10 секунд, что является временем, к которому весь объект карты должен быть истек и удален. Но это не так.
import org.apache.commons.collections4.map.PassiveExpiringMap;
import org.junit.Assert;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class PassiveExpiringMapTest {
@Test
public void givenDataMap_whenWrappingMapWithPassiveExpiringMap_thenObjectsAreRemovedWhenExpired() {
final Map<String, Integer> m = new HashMap<>();
m.put("one", Integer.valueOf(1));
m.put("two", Integer.valueOf(2));
m.put("three", Integer.valueOf(3));
PassiveExpiringMap.ConstantTimeToLiveExpirationPolicy<String, Integer>
expirationPolicy = new PassiveExpiringMap.ConstantTimeToLiveExpirationPolicy<>(
5, TimeUnit.SECONDS);
PassiveExpiringMap<String, Integer> expiringMap = new PassiveExpiringMap<>(expirationPolicy, m);
int initialCapacity = expiringMap.size();
System.out.println("initialCapacity = " initialCapacity);
Assert.assertEquals(3, initialCapacity);
System.out.println("Sleeping...");
try { Thread.sleep(10000L); } catch (InterruptedException e) { }
int updatedCapacity = expiringMap.size();
System.out.println("updatedCapacity = " updatedCapacity);
Integer one = expiringMap.get("one");
Assert.assertNull(one);
Assert.assertEquals(0, updatedCapacity);
}
}
Тест завершается ошибкой со следующим выводом:
initialCapacity = 3
Sleeping...
updatedCapacity = 3
java.lang.AssertionError: expected null, but was:<1>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotNull(Assert.java:755)
at org.junit.Assert.assertNull(Assert.java:737)
at org.junit.Assert.assertNull(Assert.java:747)
Есть идеи, чего мне не хватает?
Ответ №1:
Просмотр исходного кода PassiveExpiringMap помог мне понять, почему моя первоначальная версия не работала. Инициализация с использованием карты приводит к тому, что внутреннее поле expirationMap становится пустым. expirationMap должна содержать запись для каждого объекта, чтобы объекты с истекшим сроком действия были удалены. Для того, чтобы это произошло, необходимо использовать метод put . Приведенный ниже измененный код работает. Обратите внимание, что объекты добавляются в expiringMap напрямую, а не в HashMap, как раньше:
import org.apache.commons.collections4.map.PassiveExpiringMap;
import org.junit.Assert;
import org.junit.Test;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
public class PassiveExpiringMapTest {
@Test
public void givenDataMap_whenWrappingMapWithPassiveExpiringMap_thenObjectsAreRemovedWhenExpired() {
PassiveExpiringMap.ConstantTimeToLiveExpirationPolicy<String, Integer>
expirationPolicy = new PassiveExpiringMap.ConstantTimeToLiveExpirationPolicy<>(
5, TimeUnit.SECONDS);
PassiveExpiringMap<String, Integer> expiringMap = new PassiveExpiringMap<>(expirationPolicy, new HashMap<>());
expiringMap.put("one", Integer.valueOf(1));
expiringMap.put("two", Integer.valueOf(2));
expiringMap.put("three", Integer.valueOf(3));
int initialCapacity = expiringMap.size();
System.out.println("initialCapacity = " initialCapacity);
Assert.assertEquals(3, initialCapacity);
System.out.println("Sleeping...");
try { Thread.sleep(10000L); } catch (InterruptedException e) { }
int updatedCapacity = expiringMap.size();
System.out.println("updatedCapacity = " updatedCapacity);
Integer one = expiringMap.get("one");
Assert.assertNull(one);
Assert.assertEquals(0, updatedCapacity);
}
}
Ответ №2:
В вашем коде добавьте map ‘m’ в ‘expiringMap’
PassiveExpiringMap<String, Integer> expiringMap = new PassiveExpiringMap<>(expirationPolicy,m);
expiringMap.putAll(m);
Комментарии:
1. это работает, потому что он вызывает this.put() внутренне — см. Мой ответ.