View Javadoc

1   /*
2    *  Copyright 2003-2004 The Apache Software Foundation
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package net.sf.collections15.list;
17  
18  import java.util.List;
19  
20  import net.sf.collections15.Factory;
21  
22  /***
23   * Decorates another <code>List</code> to create objects in the list on demand.
24   * <p>
25   * When the {@link #get(int)} method is called with an index greater than
26   * the size of the list, the list will automatically grow in size and return
27   * a new object from the specified factory. The gaps will be filled by null.
28   * If a get method call encounters a null, it will be replaced with a new
29   * object from the factory. Thus this list is unsuitable for storing null
30   * objects.
31   * <p>
32   * For instance:
33   *
34   * <pre>
35   * Factory<Date> factory = new Factory<Date>() {
36   *     public Date create() {
37   *         return new Date();
38   *     }
39   * }
40   * List<Date> lazy = LazyList.<Date>decorate(new ArrayList<Date>(), factory);
41   * Date obj = lazy.get(3);
42   * </pre>
43   *
44   * After the above code is executed, <code>obj</code> will contain
45   * a new <code>Date</code> instance.  Furthermore, that <code>Date</code>
46   * instance is the fourth element in the list.  The first, second, 
47   * and third element are all set to <code>null</code>.
48   * <p>
49   * This class is Serializable from Commons Collections 3.1.
50   *
51   * @since Commons Collections 3.0
52   * @version $Revision: 1.2 $ $Date: 2005/05/25 21:25:25 $
53   * 
54   * @author Stephen Colebourne
55   * @author Arron Bates
56   * @author Paul Jack
57   */
58  public class LazyList<E> extends AbstractSerializableListDecorator<E> {
59  
60  	/*** Serialization version */
61  	private static final long serialVersionUID = 3760563096313738293L;
62  
63      /*** The factory to use to lazily instantiate the objects */
64      protected final Factory<? extends E> factory;
65  
66      /***
67       * Factory method to create a lazily instantiating list.
68       * 
69       * @param list  the list to decorate, must not be null
70       * @param factory  the factory to use for creation, must not be null
71       * @throws IllegalArgumentException if list or factory is null
72       */
73      public static <T> List<T> decorate(List<T> list, Factory<? extends T> factory) {
74          return new LazyList<T>(list, factory);
75      }
76      
77      //-----------------------------------------------------------------------
78      /***
79       * Constructor that wraps (not copies).
80       * 
81       * @param list  the list to decorate, must not be null
82       * @param factory  the factory to use for creation, must not be null
83       * @throws IllegalArgumentException if list or factory is null
84       */
85      protected LazyList(List<E> list, Factory<? extends E> factory) {
86          super(list);
87          if (factory == null) {
88              throw new IllegalArgumentException("Factory must not be null");
89          }
90          this.factory = factory;
91      }
92  
93      //-----------------------------------------------------------------------
94      /***
95       * Decorate the get method to perform the lazy behaviour.
96       * <p>
97       * If the requested index is greater than the current size, the list will 
98       * grow to the new size and a new object will be returned from the factory.
99       * Indexes in-between the old size and the requested size are left with a 
100      * placeholder that is replaced with a factory object when requested.
101      * 
102      * @param index  the index to retrieve
103      */
104     public E get(int index) {
105         int size = getList().size();
106         if (index < size) {
107             // within bounds, get the object
108             E object = getList().get(index);
109             if (object == null) {
110                 // item is a place holder, create new one, set and return
111                 object = factory.create();
112                 getList().set(index, object);
113                 return object;
114             } else {
115                 // good and ready to go
116                 return object;
117             }
118         } else {
119             // we have to grow the list
120             for (int i = size; i < index; i++) {
121                 getList().add(null);
122             }
123             // create our last object, set and return
124             E object = factory.create();
125             getList().add(object);
126             return object;
127         }
128     }
129 
130 
131     public List<E> subList(int fromIndex, int toIndex) {
132         List<E> sub = getList().subList(fromIndex, toIndex);
133         return new LazyList<E>(sub, factory);
134     }
135 }