View Javadoc
1   /*
2    * Licensed to The Apereo Foundation under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional
4    * information regarding copyright ownership.
5    *
6    *
7    * The Apereo Foundation licenses this file to you under the Educational
8    * Community License, Version 2.0 (the "License"); you may not use this file
9    * except in compliance with the License. You may obtain a copy of the License
10   * at:
11   *
12   *   http://opensource.org/licenses/ecl2.txt
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
17   * License for the specific language governing permissions and limitations under
18   * the License.
19   *
20   */
21  
22  package org.opencastproject.util.data;
23  
24  import java.lang.reflect.Array;
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.Dictionary;
28  import java.util.HashMap;
29  import java.util.HashSet;
30  import java.util.Hashtable;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.NoSuchElementException;
35  import java.util.Optional;
36  import java.util.Set;
37  
38  /**
39   * This class provides functions to ease and secure the handling of collections by supporting a type safe -- at least to
40   * the extent Java's type system allows -- immutable and more functional style.
41   *
42   * Note that all functions do <i>not</i> mutate input collections unless otherwise stated.
43   *
44   * @deprecated By now, all of this is natively available in Java.
45   */
46  @Deprecated
47  public final class Collections {
48    private Collections() {
49    }
50  
51    // TODO check all clients of this method since it potentially breaks!
52    @SuppressWarnings("unchecked")
53    private static <A, B> Collection<A> buildFrom(Collection<B> as) {
54      try {
55        return as.getClass().newInstance();
56      } catch (Exception e) {
57        throw new IllegalArgumentException("Type " + as.getClass() + " needs a parameterless constructor");
58      }
59    }
60  
61    /** Return the head of list <code>as</code> or <code>none</code>. */
62    public static <A> Optional<A> head(List<A> as) {
63      if (!as.isEmpty()) {
64        return Optional.of(as.get(0));
65      } else {
66        return Optional.empty();
67      }
68    }
69  
70    /** Make a string from a collection separating each element by <code>sep</code>. */
71    public static String mkString(Collection<?> as, String sep) {
72      final StringBuilder b = new StringBuilder();
73      for (Object a : as)
74        b.append(a).append(sep);
75      return b.substring(0, Math.max(b.length() - sep.length(), 0));
76    }
77  
78    /** Append source collection <code>as</code> to <code>target</code>. */
79    public static <A, T extends Collection<A>, S extends Iterable<? extends A>> T appendTo(T target, S as) {
80      for (A a : as)
81        target.add(a);
82      return target;
83    }
84  
85    /** Append source collections <code>as</code> to <code>target</code>. */
86    @SafeVarargs
87    public static <A, T extends Collection<A>, S extends Iterable<? extends A>> T appendToM(T target, S... as) {
88      for (S s : as) {
89        for (A a : s)
90          target.add(a);
91      }
92      return target;
93    }
94  
95    /** Append source collections <code>as</code> to <code>target</code>. */
96    @SafeVarargs
97    public static <A, T extends Collection<A>, X extends A> T appendToA(T target, X... as) {
98      java.util.Collections.addAll(target, as);
99      return target;
100   }
101 
102   /** Concatenates two iterables into a new list. */
103   public static <A, M extends Iterable<? extends A>> List<A> concat(M as, M bs) {
104     List<A> x = new ArrayList<>();
105     for (A a : as)
106       x.add(a);
107     for (A b : bs)
108       x.add(b);
109     return x;
110   }
111 
112   /**
113    * Merge two maps where <code>b</code> takes precedence.
114    *
115    * @return a new immutable map
116    */
117   public static <A, B> Map<A, B> merge(Map<? extends A, ? extends B> a, Map<? extends A, ? extends B> b) {
118     final Map<A, B> x = new HashMap<>();
119     x.putAll(a);
120     x.putAll(b);
121     return java.util.Collections.unmodifiableMap(x);
122   }
123 
124   /** Drain all elements of <code>as</code> into a list. */
125   public static <A> List<A> toList(Iterator<? extends A> as) {
126     final List<A> t = new ArrayList<>();
127     while (as.hasNext()) {
128       t.add(as.next());
129     }
130     return t;
131   }
132 
133   /** Drain all elements of <code>as</code> into a list. */
134   public static <A> List<A> toList(Collection<A> as) {
135     return new ArrayList<>(as);
136   }
137 
138   /**
139    * Return the list as is or nil, if <code>as</code> is null.
140    * 
141    * @deprecated use {@link #nullToNil(java.util.List)}
142    */
143   @Deprecated
144   public static <A> List<A> mkList(List<A> as) {
145     return as != null ? as : Collections.<A> nil();
146   }
147 
148   /** Return the list as is or nil, if <code>as</code> is null. */
149   public static <A> List<A> nullToNil(List<A> as) {
150     return as != null ? as : Collections.<A> nil();
151   }
152 
153   /** Create a list from an array. */
154   @SafeVarargs
155   public static <A> List<A> list(A... as) {
156     final List<A> t = new ArrayList<>();
157     java.util.Collections.addAll(t, as);
158     return t;
159   }
160 
161   /** Create a list from an array. */
162   @SafeVarargs
163   public static <A> List<A> nonNullList(A... as) {
164     final List<A> t = new ArrayList<>();
165     for (A a : as) {
166       if (null != a) {
167         t.add(a);
168       }
169     }
170     return t;
171   }
172 
173   /** The empty list. */
174   @SuppressWarnings("unchecked")
175   public static <A> List<A> nil() {
176     return java.util.Collections.EMPTY_LIST;
177   }
178 
179   /** The empty list. */
180   @SuppressWarnings("unchecked")
181   public static <A> List<A> nil(Class<A> type) {
182     return java.util.Collections.EMPTY_LIST;
183   }
184 
185   /** Construct a new list by prepending an element to a given list. */
186   public static <A> List<A> cons(A a, List<? extends A> as) {
187     final List<A> target = new ArrayList<>(as.size() + 1);
188     target.add(a);
189     target.addAll(as);
190     return target;
191   }
192 
193   /** Create a set from an array. */
194   @SafeVarargs
195   public static <A> Set<A> set(A... as) {
196     final Set<A> t = new HashSet<>(as.length);
197     java.util.Collections.addAll(t, as);
198     return t;
199   }
200 
201   /** Create a set from a list. */
202   public static <A> Set<A> toSet(List<A> as) {
203     Set<A> r = new HashSet<>(as.size());
204     for (A a : as)
205       r.add(a);
206     return r;
207   }
208 
209   /** Create a map from a list of tuples (K, V). */
210   @SafeVarargs
211   public static <K, V> Map<K, V> map(Tuple<? extends K, ? extends V>... ts) {
212     final Map<K, V> map = new HashMap<>(ts.length);
213     for (Tuple<? extends K, ? extends V> t : ts) {
214       map.put(t.getA(), t.getB());
215     }
216     return map;
217   }
218 
219   /** Create a dictionary from a list of tuples (K, V). */
220   @SafeVarargs
221   public static <K, V> Dictionary<K, V> dict(Tuple<? extends K, ? extends V>... ts) {
222     final Dictionary<K, V> dict = new Hashtable<>(ts.length);
223     for (Tuple<? extends K, ? extends V> t : ts) {
224       dict.put(t.getA(), t.getB());
225     }
226     return dict;
227   }
228 
229   /** Create an array from a collection. */
230   @SuppressWarnings("unchecked")
231   public static <A, B extends A> A[] toArray(Class<A> elemType, Collection<B> a) {
232     return a.toArray((A[]) Array.newInstance(elemType, a.size()));
233   }
234 
235   /** Convert a collection of {@link Double}s into an array of primitive type. */
236   public static double[] toDoubleArray(Collection<Double> as) {
237     final double[] target = new double[as.size()];
238     int i = 0;
239     for (Double a : as) {
240       target[i] = a;
241       i++;
242     }
243     return target;
244   }
245 
246   /** Create an iterator form an array. */
247   @SafeVarargs
248   public static <A> Iterator<A> iterator(final A... as) {
249     return new Iterator<A>() {
250       private int i = 0;
251 
252       @Override
253       public boolean hasNext() {
254         return as.length > i;
255       }
256 
257       @Override
258       public A next() {
259         if (i < as.length) {
260           return as[i++];
261         } else {
262           throw new NoSuchElementException();
263         }
264       }
265 
266       @Override
267       public void remove() {
268         throw new UnsupportedOperationException();
269       }
270     };
271   }
272 
273   /** Create an iterator that repeats <code>a</code> for the said times. */
274   public static <A, X extends A> Iterator<A> repeat(final X a, final int times) {
275     return new Iterator<A>() {
276       private int count = times;
277 
278       @Override
279       public boolean hasNext() {
280         return count > 0;
281       }
282 
283       @Override
284       public A next() {
285         count--;
286         return a;
287       }
288 
289       @Override
290       public void remove() {
291         throw new UnsupportedOperationException();
292       }
293     };
294   }
295 
296   /** Join two iterators. */
297   public static <A> Iterator<A> join(final Iterator<A> a, final Iterator<A> b) {
298     return new Iterator<A>() {
299       @Override
300       public boolean hasNext() {
301         return a.hasNext() || b.hasNext();
302       }
303 
304       @Override
305       public A next() {
306         return a.hasNext() ? a.next() : b.next();
307       }
308 
309       @Override
310       public void remove() {
311         throw new UnsupportedOperationException();
312       }
313     };
314   }
315 
316   /**
317    * Make an Iterator usable in a for comprehension like this:
318    *
319    * <pre>
320    *   Iterator&lt;A&gt; as = ...
321    *   for (A a : forc(as)) {
322    *     ...
323    *   }
324    * </pre>
325    */
326   public static <A> Iterable<A> forc(final Iterator<A> as) {
327     return new Iterable<A>() {
328       @Override
329       public Iterator<A> iterator() {
330         return as;
331       }
332     };
333   }
334 
335   /** Concat (aka flatten) a collection of collections by concatenating them all. [[a]] -&gt; [a] */
336   public static <A, M extends Collection<? extends Collection<A>>> List<A> concat(M as) {
337     final List<A> target = new ArrayList<>(as.size());
338     for (Collection<A> a : as) {
339       target.addAll(a);
340     }
341     return target;
342   }
343 
344 }