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