1 /*
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
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  * A copy of the License is located at
7  *
8  *  http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */

15
16 package software.amazon.awssdk.utils;
17
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.LinkedHashMap;
21 import java.util.LinkedList;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.function.Function;
25 import java.util.function.Supplier;
26 import java.util.stream.Collector;
27 import java.util.stream.Collectors;
28 import software.amazon.awssdk.annotations.SdkProtectedApi;
29
30 @SdkProtectedApi
31 public final class CollectionUtils {
32
33     private CollectionUtils() {
34     }
35
36     public static boolean isNullOrEmpty(Collection<?> collection) {
37         return collection == null || collection.isEmpty();
38     }
39
40     public static boolean isNullOrEmpty(Map<?, ?> map) {
41         return map == null || map.isEmpty();
42     }
43
44     /**
45      * Returns a new list containing the second list appended to the first list.
46      */

47     public static <T> List<T> mergeLists(List<T> list1, List<T> list2) {
48         List<T> merged = new LinkedList<>();
49         if (list1 != null) {
50             merged.addAll(list1);
51         }
52         if (list2 != null) {
53             merged.addAll(list2);
54         }
55         return merged;
56     }
57
58     /**
59      * @param list List to get first element from.
60      * @param <T> Type of elements in the list.
61      * @return The first element in the list if it exists. If the list is null or empty this will
62      * return null.
63      */

64     public static <T> T firstIfPresent(List<T> list) {
65         if (list == null || list.isEmpty()) {
66             return null;
67         } else {
68             return list.get(0);
69         }
70     }
71
72     /**
73      * Perform a deep copy of the provided map of lists. This only performs a deep copy of the map and lists. Entries are not
74      * copied, so care should be taken to ensure that entries are immutable if preventing unwanted mutations of the elements is
75      * desired.
76      */

77     public static <T, U> Map<T, List<U>> deepCopyMap(Map<T, ? extends List<U>> map) {
78         return deepCopyMap(map, () -> new LinkedHashMap<>());
79     }
80
81     /**
82      * Perform a deep copy of the provided map of lists. This only performs a deep copy of the map and lists. Entries are not
83      * copied, so care should be taken to ensure that entries are immutable if preventing unwanted mutations of the elements is
84      * desired.
85      */

86     public static <T, U> Map<T, List<U>> deepCopyMap(Map<T, ? extends List<U>> map, Supplier<Map<T, List<U>>> mapConstructor) {
87         Map<T, List<U>> result = mapConstructor.get();
88         map.forEach((k, v) -> result.put(k, new ArrayList<>(v)));
89         return result;
90     }
91
92     public static <T, U> Map<T, List<U>> unmodifiableMapOfLists(Map<T, List<U>> map) {
93         return new UnmodifiableMapOfLists<>(map);
94     }
95
96     /**
97      * Perform a deep copy of the provided map of lists, and make the result unmodifiable.
98      *
99      * This is equivalent to calling {@link #deepCopyMap} followed by {@link #unmodifiableMapOfLists}.
100      */

101     public static <T, U> Map<T, List<U>> deepUnmodifiableMap(Map<T, ? extends List<U>> map) {
102         return unmodifiableMapOfLists(deepCopyMap(map));
103     }
104
105     /**
106      * Perform a deep copy of the provided map of lists, and make the result unmodifiable.
107      *
108      * This is equivalent to calling {@link #deepCopyMap} followed by {@link #unmodifiableMapOfLists}.
109      */

110     public static <T, U> Map<T, List<U>> deepUnmodifiableMap(Map<T, ? extends List<U>> map,
111                                                              Supplier<Map<T, List<U>>> mapConstructor) {
112         return unmodifiableMapOfLists(deepCopyMap(map, mapConstructor));
113     }
114
115
116     /**
117      * Collect a stream of {@link Map.Entry} to a {@link Map} with the same key/value types
118      * @param <K> the key type
119      * @param <V> the value type
120      * @return a map
121      */

122     public static <K, V> Collector<Map.Entry<K, V>, ?, Map<K, V>> toMap() {
123         return Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue);
124     }
125
126     public static <K, VInT, VOutT> Map<K, VOutT> mapValues(Map<K, VInT> inputMap, Function<VInT, VOutT> mapper) {
127         return inputMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> mapper.apply(e.getValue())));
128     }
129 }
130