Add lazyMap versions that use a Transformer as their factory.
These are in fact incredibly powerful, especially if wrapped in a synchronized wrapper. In this case it forms a self-populating cache. Idea by Dennis Mitchell, bugzilla ref 17953 git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk@130994 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
7f942e98b6
commit
af6d9f164f
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/MapUtils.java,v 1.18 2003/04/06 19:32:18 scolebourne Exp $
|
||||
* $Revision: 1.18 $
|
||||
* $Date: 2003/04/06 19:32:18 $
|
||||
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/MapUtils.java,v 1.19 2003/04/06 20:07:55 scolebourne Exp $
|
||||
* $Revision: 1.19 $
|
||||
* $Date: 2003/04/06 20:07:55 $
|
||||
*
|
||||
* ====================================================================
|
||||
*
|
||||
|
@ -963,6 +963,37 @@ public class MapUtils {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of a map that creates objects on demand.
|
||||
*/
|
||||
static class LazyTransformerMap
|
||||
extends ProxyMap {
|
||||
|
||||
protected final Transformer transformer;
|
||||
|
||||
public LazyTransformerMap(Map map, Transformer transformer) {
|
||||
super(map);
|
||||
if (map == null) {
|
||||
throw new IllegalArgumentException("Map must not be null");
|
||||
}
|
||||
if (transformer == null) {
|
||||
throw new IllegalArgumentException("Transformer must not be null");
|
||||
}
|
||||
this.transformer = transformer;
|
||||
}
|
||||
|
||||
|
||||
public Object get(Object key) {
|
||||
if (!map.containsKey(key)) {
|
||||
Object value = transformer.transform(key);
|
||||
map.put(key, value);
|
||||
return value;
|
||||
}
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of a sorted map that checks additions.
|
||||
*/
|
||||
|
@ -978,17 +1009,14 @@ public class MapUtils {
|
|||
return getSortedMap().firstKey();
|
||||
}
|
||||
|
||||
|
||||
public Object lastKey() {
|
||||
return getSortedMap().lastKey();
|
||||
}
|
||||
|
||||
|
||||
public Comparator comparator() {
|
||||
return getSortedMap().comparator();
|
||||
}
|
||||
|
||||
|
||||
public SortedMap subMap(Object o1, Object o2) {
|
||||
SortedMap sub = getSortedMap().subMap(o1, o2);
|
||||
return new PredicatedSortedMap(sub, keyPredicate, valuePredicate);
|
||||
|
@ -1025,17 +1053,14 @@ public class MapUtils {
|
|||
return getSortedMap().firstKey();
|
||||
}
|
||||
|
||||
|
||||
public Object lastKey() {
|
||||
return getSortedMap().lastKey();
|
||||
}
|
||||
|
||||
|
||||
public Comparator comparator() {
|
||||
return getSortedMap().comparator();
|
||||
}
|
||||
|
||||
|
||||
public SortedMap subMap(Object o1, Object o2) {
|
||||
return new FixedSizeSortedMap(getSortedMap().subMap(o1, o2));
|
||||
}
|
||||
|
@ -1069,17 +1094,14 @@ public class MapUtils {
|
|||
return getSortedMap().firstKey();
|
||||
}
|
||||
|
||||
|
||||
public Object lastKey() {
|
||||
return getSortedMap().lastKey();
|
||||
}
|
||||
|
||||
|
||||
public Comparator comparator() {
|
||||
return getSortedMap().comparator();
|
||||
}
|
||||
|
||||
|
||||
public SortedMap subMap(Object o1, Object o2) {
|
||||
return new LazySortedMap(getSortedMap().subMap(o1, o2), factory);
|
||||
}
|
||||
|
@ -1098,6 +1120,47 @@ public class MapUtils {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of a sorted map that creates objects on demand.
|
||||
*/
|
||||
static class LazyTransformerSortedMap
|
||||
extends LazyTransformerMap
|
||||
implements SortedMap {
|
||||
|
||||
public LazyTransformerSortedMap(SortedMap m, Transformer transformer) {
|
||||
super(m, transformer);
|
||||
}
|
||||
|
||||
public Object firstKey() {
|
||||
return getSortedMap().firstKey();
|
||||
}
|
||||
|
||||
public Object lastKey() {
|
||||
return getSortedMap().lastKey();
|
||||
}
|
||||
|
||||
public Comparator comparator() {
|
||||
return getSortedMap().comparator();
|
||||
}
|
||||
|
||||
public SortedMap subMap(Object o1, Object o2) {
|
||||
return new LazyTransformerSortedMap(getSortedMap().subMap(o1, o2), transformer);
|
||||
}
|
||||
|
||||
public SortedMap headMap(Object o1) {
|
||||
return new LazyTransformerSortedMap(getSortedMap().headMap(o1), transformer);
|
||||
}
|
||||
|
||||
public SortedMap tailMap(Object o1) {
|
||||
return new LazyTransformerSortedMap(getSortedMap().tailMap(o1), transformer);
|
||||
}
|
||||
|
||||
private SortedMap getSortedMap() {
|
||||
return (SortedMap)map;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns a synchronized map backed by the given map.
|
||||
|
@ -1187,7 +1250,7 @@ public class MapUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a "lazy" map whose values will be created on demand.<P>
|
||||
* Returns a "lazy" map whose values will be created on demand.
|
||||
* <p>
|
||||
* When the key passed to the returned map's {@link Map#get(Object)}
|
||||
* method is not present in the map, then the factory will be used
|
||||
|
@ -1195,20 +1258,19 @@ public class MapUtils {
|
|||
* associated with that key.
|
||||
* <p>
|
||||
* For instance:
|
||||
*
|
||||
* <pre>
|
||||
* Factory factory = new Factory() {
|
||||
* public Object create() {
|
||||
* return new Date();
|
||||
* }
|
||||
* }
|
||||
* Map lazy = MapUtils.lazyMap(new HashMap(), factory);
|
||||
* Object obj = lazy.get("test");
|
||||
* Map lazyMap = MapUtils.lazyMap(new HashMap(), factory);
|
||||
* Object obj = lazyMap.get("test");
|
||||
* </pre>
|
||||
*
|
||||
* After the above code is executed, <code>obj</code> will contain
|
||||
* a new <code>Date</code> instance. Furthermore, that <code>Date</code>
|
||||
* instance is the value for the <code>test</code> key.
|
||||
* instance is the value for the <code>"test"</code> key in the map.
|
||||
*
|
||||
* @param map the map to make lazy, must not be null
|
||||
* @param factory the factory for creating new objects, must not be null
|
||||
|
@ -1219,6 +1281,45 @@ public class MapUtils {
|
|||
return new LazyMap(map, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a "lazy" map whose values will be created on demand.
|
||||
* <p>
|
||||
* When the key passed to the returned map's {@link Map#get(Object)}
|
||||
* method is not present in the map, then the factory will be used
|
||||
* to create a new object and that object will become the value
|
||||
* associated with that key. The factory is a {@link Transformer}
|
||||
* that will be passed the key which it must transform into the value.
|
||||
* <p>
|
||||
* For instance:
|
||||
* <pre>
|
||||
* Transformer factory = new Transformer() {
|
||||
* public Object transform(Object mapKey) {
|
||||
* return new File(mapKey);
|
||||
* }
|
||||
* }
|
||||
* Map lazyMap = MapUtils.lazyMap(new HashMap(), factory);
|
||||
* Object obj = lazyMap.get("C:/dev");
|
||||
* </pre>
|
||||
*
|
||||
* After the above code is executed, <code>obj</code> will contain
|
||||
* a new <code>File</code> instance for the C drive dev directory.
|
||||
* Furthermore, that <code>File</code> instance is the value for the
|
||||
* <code>"C:/dev"</code> key in the map.
|
||||
* <p>
|
||||
* If a lazy map is wrapped by a synchronized map, the result is a simple
|
||||
* synchronized cache. When an object is not is the cache, the cache itself
|
||||
* calls back to the factory Transformer to populate itself, all within the
|
||||
* same synchronized block.
|
||||
*
|
||||
* @param map the map to make lazy, must not be null
|
||||
* @param transformerFactory the factory for creating new objects, must not be null
|
||||
* @return a lazy map backed by the given map
|
||||
* @throws IllegalArgumentException if the Map or Transformer is null
|
||||
*/
|
||||
public static Map lazyMap(Map map, Transformer transformerFactory) {
|
||||
return new LazyTransformerMap(map, transformerFactory);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns a synchronized sorted map backed by the given sorted map.
|
||||
|
@ -1329,7 +1430,7 @@ public class MapUtils {
|
|||
*
|
||||
* After the above code is executed, <code>obj</code> will contain
|
||||
* a new <code>Date</code> instance. Furthermore, that <code>Date</code>
|
||||
* instance is the value for the <code>test</code> key.
|
||||
* instance is the value for the <code>"test"</code> key.
|
||||
*
|
||||
* @param map the map to make lazy, must not be null
|
||||
* @param factory the factory for creating new objects, must not be null
|
||||
|
@ -1340,4 +1441,43 @@ public class MapUtils {
|
|||
return new LazySortedMap(map, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a "lazy" sorted map whose values will be created on demand.
|
||||
* <p>
|
||||
* When the key passed to the returned map's {@link Map#get(Object)}
|
||||
* method is not present in the map, then the factory will be used
|
||||
* to create a new object and that object will become the value
|
||||
* associated with that key. The factory is a {@link Transformer}
|
||||
* that will be passed the key which it must transform into the value.
|
||||
* <p>
|
||||
* For instance:
|
||||
* <pre>
|
||||
* Transformer factory = new Transformer() {
|
||||
* public Object transform(Object mapKey) {
|
||||
* return new File(mapKey);
|
||||
* }
|
||||
* }
|
||||
* Map lazyMap = MapUtils.lazyMap(new HashMap(), factory);
|
||||
* Object obj = lazyMap.get("C:/dev");
|
||||
* </pre>
|
||||
*
|
||||
* After the above code is executed, <code>obj</code> will contain
|
||||
* a new <code>File</code> instance for the C drive dev directory.
|
||||
* Furthermore, that <code>File</code> instance is the value for the
|
||||
* <code>"C:/dev"</code> key in the map.
|
||||
* <p>
|
||||
* If a lazy map is wrapped by a synchronized map, the result is a simple
|
||||
* synchronized cache. When an object is not is the cache, the cache itself
|
||||
* calls back to the factory Transformer to populate itself, all within the
|
||||
* same synchronized block.
|
||||
*
|
||||
* @param map the map to make lazy, must not be null
|
||||
* @param transformerFactory the factory for creating new objects, must not be null
|
||||
* @return a lazy map backed by the given map
|
||||
* @throws IllegalArgumentException if the Map or Transformer is null
|
||||
*/
|
||||
public static SortedMap lazySortedMap(SortedMap map, Transformer transformerFactory) {
|
||||
return new LazyTransformerSortedMap(map, transformerFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/TestMapUtils.java,v 1.3 2003/04/04 22:22:28 scolebourne Exp $
|
||||
* $Revision: 1.3 $
|
||||
* $Date: 2003/04/04 22:22:28 $
|
||||
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/TestMapUtils.java,v 1.4 2003/04/06 20:07:55 scolebourne Exp $
|
||||
* $Revision: 1.4 $
|
||||
* $Date: 2003/04/06 20:07:55 $
|
||||
*
|
||||
* ====================================================================
|
||||
*
|
||||
|
@ -213,5 +213,41 @@ public class TestMapUtils extends BulkTest {
|
|||
};
|
||||
}
|
||||
|
||||
public void testLazyMapFactory() {
|
||||
Map map = MapUtils.lazyMap(new HashMap(), new Factory() {
|
||||
public Object create() {
|
||||
return new Integer(5);
|
||||
}
|
||||
});
|
||||
|
||||
assertEquals(0, map.size());
|
||||
Integer i1 = (Integer) map.get("Five");
|
||||
assertEquals(new Integer(5), i1);
|
||||
assertEquals(1, map.size());
|
||||
Integer i2 = (Integer) map.get(new String(new char[] {'F','i','v','e'}));
|
||||
assertEquals(new Integer(5), i2);
|
||||
assertEquals(1, map.size());
|
||||
assertSame(i1, i2);
|
||||
}
|
||||
|
||||
public void testLazyMapTransformer() {
|
||||
Map map = MapUtils.lazyMap(new HashMap(), new Transformer() {
|
||||
public Object transform(Object mapKey) {
|
||||
if (mapKey instanceof String) {
|
||||
return new Integer((String) mapKey);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
assertEquals(0, map.size());
|
||||
Integer i1 = (Integer) map.get("5");
|
||||
assertEquals(new Integer(5), i1);
|
||||
assertEquals(1, map.size());
|
||||
Integer i2 = (Integer) map.get(new String(new char[] {'5'}));
|
||||
assertEquals(new Integer(5), i2);
|
||||
assertEquals(1, map.size());
|
||||
assertSame(i1, i2);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue