001/*
002 * Copyright 2023 the original author or authors.
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * https://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package de.cuioss.tools.collect;
017
018import static de.cuioss.tools.base.Preconditions.checkArgument;
019
020import java.util.Collection;
021import java.util.Iterator;
022import java.util.Map;
023import java.util.stream.Stream;
024
025import lombok.experimental.UtilityClass;
026
027/**
028 * <h2>Overview</h2> Utility Methods for Collections and some types to be used
029 * in the context of Collections.
030 *
031 * <h3>isEmpty()</h3> The overloaded method
032 * {@link MoreCollections#isEmpty(Collection)} checks all kinds of Collections /
033 * varargs parameter for not being null and emptiness. In case of
034 * {@link Stream}s it solely checks for being not null in order not to consume
035 * it.
036 *
037 * <h3>requireNotEmpty()</h3> The overloaded method
038 * {@link MoreCollections#requireNotEmpty(Collection)} checks all kinds of
039 * Collections / varargs parameter for not being null nor empty. In case of
040 * being null / empty they will throw an {@link IllegalArgumentException}
041 *
042 * <h3>Map Difference</h3> The method
043 * {@link MoreCollections#difference(Map, Map)} creates an {@link MapDifference}
044 * view on the two given maps in order to check, well whether they are equal or
045 * not and if not which elements are differing.
046 *
047 * <h3>Map contains key</h3> Check whether the given Map contains at least one
048 * of the given keys (varags)
049 *
050 * @author Oliver Wolff
051 *
052 */
053@UtilityClass
054public final class MoreCollections {
055
056    /**
057     * Simple check method for a {@code null} safe check of the emptiness of the
058     * given varags-parameter.
059     *
060     * @param elements to be checked, may be null
061     * @return {@code true} is the given elements are {@code null} or {@code empty}
062     */
063    public static boolean isEmpty(Object... elements) {
064        return null == elements || 0 == elements.length;
065    }
066
067    /**
068     * Simple check method for a {@code null} safe check of the emptiness of the
069     * given parameter.
070     *
071     * @param elements to be checked, may be null
072     * @return {@code true} is the given elements are {@code null} or {@code empty}
073     */
074    public static boolean isEmpty(Iterable<?> elements) {
075        return null == elements || isEmpty(elements.iterator());
076    }
077
078    /**
079     * Simple check method for a {@code null} safe check of the emptiness of the
080     * given parameter.
081     *
082     * @param elements to be checked, may be null
083     * @return {@code true} is the given elements are {@code null} or {@code empty}
084     */
085    public static boolean isEmpty(Collection<?> elements) {
086        return null == elements || elements.isEmpty();
087    }
088
089    /**
090     * Simple check method for a {@code null} safe check of the emptiness of the
091     * given parameter.
092     *
093     * @param map to be checked, may be null
094     * @return {@code true} is the given elements are {@code null} or {@code empty}
095     */
096    public static boolean isEmpty(Map<?, ?> map) {
097        return null == map || map.isEmpty();
098    }
099
100    /**
101     * Simple check method for a {@code null} safe check of the emptiness of the
102     * given parameter.
103     *
104     * @param elements to be checked, may be null
105     * @return {@code true} is the given elements are {@code null} or {@code empty}
106     */
107    public static boolean isEmpty(Iterator<?> elements) {
108        return null == elements || !elements.hasNext();
109    }
110
111    /**
112     * Shorthand for checking whether the given elements are empty or not.
113     *
114     * @param <T>      identifying the type to be checked
115     * @param elements to be checked
116     * @return the given parameter
117     * @throws IllegalArgumentException in case the given elements are {@code null}
118     *                                  or empty
119     */
120    @SafeVarargs
121    public static <T> T[] requireNotEmpty(T... elements) {
122        checkArgument(!isEmpty(elements));
123        return elements;
124    }
125
126    /**
127     * Shorthand for checking whether the given elements are empty or not.
128     *
129     * @param <T>      identifying the type to be checked
130     * @param elements to be checked
131     * @return the given parameter
132     * @throws IllegalArgumentException in case the given elements are {@code null}
133     *                                  or empty
134     */
135    public static <T> Collection<T> requireNotEmpty(Collection<T> elements) {
136        checkArgument(!isEmpty(elements));
137        return elements;
138    }
139
140    /**
141     * Shorthand for checking whether the given elements are empty or not.
142     *
143     * @param <T>      identifying the type to be checked
144     * @param elements to be checked
145     * @param message  to be set in error-case
146     * @return the given parameter
147     * @throws IllegalArgumentException in case the given elements are {@code null}
148     *                                  or empty
149     */
150    public static <T> Collection<T> requireNotEmpty(Collection<T> elements, String message) {
151        checkArgument(!isEmpty(elements), message);
152        return elements;
153    }
154
155    /**
156     * Shorthand for checking whether the given elements are empty or not.
157     *
158     * @param <K>      the type for the key
159     * @param <V>      the type for the value
160     * @param elements to be checked
161     * @return the given parameter
162     * @throws IllegalArgumentException in case the given elements are {@code null}
163     *                                  or empty
164     */
165    public static <K, V> Map<K, V> requireNotEmpty(Map<K, V> elements) {
166        checkArgument(!isEmpty(elements));
167        return elements;
168    }
169
170    /**
171     * Shorthand for checking whether the given elements are empty or not.
172     *
173     * @param <K>      the type for the key
174     * @param <V>      the type for the value
175     * @param elements to be checked
176     * @param message  to be set in error-case
177     * @return the given parameter
178     * @throws IllegalArgumentException in case the given elements are {@code null}
179     *                                  or empty
180     */
181    public static <K, V> Map<K, V> requireNotEmpty(Map<K, V> elements, String message) {
182        checkArgument(!isEmpty(elements), message);
183        return elements;
184    }
185
186    /**
187     * Shorthand for checking whether the given elements are empty or not.
188     *
189     * @param <T>      identifying the type to be checked
190     * @param elements to be checked
191     * @return the given parameter
192     * @throws IllegalArgumentException in case the given elements are {@code null}
193     *                                  or empty
194     */
195    public static <T> Iterable<T> requireNotEmpty(Iterable<T> elements) {
196        checkArgument(!isEmpty(elements));
197        return elements;
198    }
199
200    /**
201     * Shorthand for checking whether the given elements are empty or not.
202     *
203     * @param <T>      identifying the type to be checked
204     * @param elements to be checked
205     * @param message  to be set in error-case
206     * @return the given parameter
207     * @throws IllegalArgumentException in case the given elements are {@code null}
208     *                                  or empty
209     */
210    public static <T> Iterable<T> requireNotEmpty(Iterable<T> elements, String message) {
211        checkArgument(!isEmpty(elements), message);
212        return elements;
213    }
214
215    /**
216     * Shorthand for checking whether the given elements are empty or not.
217     *
218     * @param elements to be checked
219     * @return the given parameter
220     * @throws IllegalArgumentException in case the given elements are {@code null}
221     *                                  or empty
222     */
223    public static <T> Iterator<T> requireNotEmpty(Iterator<T> elements) {
224        checkArgument(!isEmpty(elements));
225        return elements;
226    }
227
228    /**
229     * Shorthand for checking whether the given elements are empty or not.
230     *
231     * @param <T>      identifying the type to be checked
232     * @param elements to be checked
233     * @param message  to be set in error-case
234     * @return the given parameter
235     * @throws IllegalArgumentException in case the given elements are {@code null}
236     *                                  or empty
237     */
238    public static <T> Iterator<T> requireNotEmpty(Iterator<T> elements, String message) {
239        checkArgument(!isEmpty(elements), message);
240        return elements;
241    }
242
243    /**
244     * Shorthand for checking whether the given elements are empty or not.
245     * <em>Caution: </em> In order not to consume the stream only a null check will
246     * be performed.
247     *
248     * @param <T>      identifying the type to be checked
249     * @param elements to be checked
250     * @return the given parameter
251     * @throws IllegalArgumentException in case the given elements are {@code null}
252     */
253    public static <T> Stream<T> requireNotEmpty(Stream<T> elements) {
254        checkArgument(!isEmpty(elements));
255        return elements;
256    }
257
258    /**
259     * Shorthand for checking whether the given elements are empty or not.
260     * <em>Caution: </em> In order not to consume the stream only a null check will
261     * be performed.
262     *
263     * @param <T>      identifying the type to be checked
264     * @param elements to be checked
265     * @param message  to be set in error-case
266     * @return the given parameter
267     * @throws IllegalArgumentException in case the given elements are {@code null}
268     */
269    public static <T> Stream<T> requireNotEmpty(Stream<T> elements, String message) {
270        checkArgument(!isEmpty(elements), message);
271        return elements;
272    }
273
274    /**
275     * Simple check method for a {@code null} safe check of the emptiness of the
276     * given parameter. <em>Caution: </em> In order not to consume the stream only a
277     * null check will be performed.
278     *
279     * @param elements to be checked, may be null
280     * @return {@code true} is the given elements are {@code null}. The Stream
281     *         content will be untouched
282     * @throws IllegalArgumentException in case the given elements are {@code null}
283     */
284    public static boolean isEmpty(Stream<?> elements) {
285        return null == elements;
286    }
287
288    /**
289     * Checks whether the given map contains at least one of the given keys to be
290     * checked.
291     *
292     * @param map  to be checked. If it is {@code null} or empty the method will
293     *             always return {@code false}
294     * @param keys to be checked. If it is {@code null} or empty the method will
295     *             always return {@code false}
296     * @return {@code true} if the map contains at lest one of the given keys,
297     *         {@code false} otherwise
298     */
299    public static boolean containsKey(Map<?, ?> map, Object... keys) {
300        if (isEmpty(map) || isEmpty(keys)) {
301            return false;
302        }
303        for (Object key : keys) {
304            if (map.containsKey(key)) {
305                return true;
306            }
307        }
308        return false;
309    }
310
311    /**
312     * Computes the difference between two maps. This difference is an immutable
313     * snapshot of the state of the maps at the time this method is called. It will
314     * never change, even if the maps change at a later time.
315     *
316     * <p>
317     * Since this method uses {@code HashMap} instances internally, the keys of the
318     * supplied maps must be well-behaved with respect to {@link Object#equals} and
319     * {@link Object#hashCode}.
320     *
321     * <p>
322     * <b>Note:</b>If you only need to know whether two maps have the same mappings,
323     * call {@code
324     * left.equals(right)} instead of this method.
325     *
326     * @param <K>   the type for the key
327     * @param <V>   the type for the value
328     * @param left  the map to treat as the "left" map for purposes of comparison,
329     *              must not be null
330     * @param right the map to treat as the "right" map for purposes of comparison ,
331     *              must not be null
332     * @return the difference between the two maps
333     *
334     * @author com.google.common.collect.MapDifference<K, V>
335     */
336    public static <K, V> MapDifference<K, V> difference(Map<? extends K, ? extends V> left,
337            Map<? extends K, ? extends V> right) {
338        return MapDiffenceImpl.from(left, right);
339    }
340
341}