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