1 /* 2 * Copyright (C) 2017 The Android Open Source Project 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 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.util; 18 19 import static com.android.internal.util.ArrayUtils.isEmpty; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 24 import java.util.ArrayList; 25 import java.util.Collection; 26 import java.util.Collections; 27 import java.util.List; 28 import java.util.Set; 29 import java.util.function.Function; 30 import java.util.stream.Stream; 31 32 /** 33 * Utility methods for dealing with (typically {@link Nullable}) {@link Collection}s 34 * 35 * Unless a method specifies otherwise, a null value for a collection is treated as an empty 36 * collection of that type. 37 */ 38 public class CollectionUtils { CollectionUtils()39 private CollectionUtils() { /* cannot be instantiated */ } 40 41 /** 42 * Returns a list of items from the provided list that match the given condition. 43 * 44 * This is similar to {@link Stream#filter} but without the overhead of creating an intermediate 45 * {@link Stream} instance 46 */ filter(@ullable List<T> list, java.util.function.Predicate<? super T> predicate)47 public static @NonNull <T> List<T> filter(@Nullable List<T> list, 48 java.util.function.Predicate<? super T> predicate) { 49 ArrayList<T> result = null; 50 for (int i = 0; i < size(list); i++) { 51 final T item = list.get(i); 52 if (predicate.test(item)) { 53 result = ArrayUtils.add(result, item); 54 } 55 } 56 return emptyIfNull(result); 57 } 58 59 /** 60 * Returns a list of items resulting from applying the given function to each element of the 61 * provided list. 62 * 63 * The resulting list will have the same {@link #size} as the input one. 64 * 65 * This is similar to {@link Stream#map} but without the overhead of creating an intermediate 66 * {@link Stream} instance 67 */ map(@ullable List<I> cur, Function<? super I, ? extends O> f)68 public static @NonNull <I, O> List<O> map(@Nullable List<I> cur, 69 Function<? super I, ? extends O> f) { 70 if (isEmpty(cur)) return Collections.emptyList(); 71 final ArrayList<O> result = new ArrayList<>(); 72 for (int i = 0; i < cur.size(); i++) { 73 result.add(f.apply(cur.get(i))); 74 } 75 return result; 76 } 77 78 /** 79 * {@link #map(List, Function)} + {@link #filter(List, java.util.function.Predicate)} 80 * 81 * Calling this is equivalent (but more memory efficient) to: 82 * 83 * {@code 84 * filter( 85 * map(cur, f), 86 * i -> { i != null }) 87 * } 88 */ mapNotNull(@ullable List<I> cur, Function<? super I, ? extends O> f)89 public static @NonNull <I, O> List<O> mapNotNull(@Nullable List<I> cur, 90 Function<? super I, ? extends O> f) { 91 if (isEmpty(cur)) return Collections.emptyList(); 92 final ArrayList<O> result = new ArrayList<>(); 93 for (int i = 0; i < cur.size(); i++) { 94 O transformed = f.apply(cur.get(i)); 95 if (transformed != null) { 96 result.add(transformed); 97 } 98 } 99 return result; 100 } 101 102 /** 103 * Returns the given list, or an immutable empty list if the provided list is null 104 * 105 * This can be used to guarantee null-safety without paying the price of extra allocations 106 * 107 * @see Collections#emptyList 108 */ emptyIfNull(@ullable List<T> cur)109 public static @NonNull <T> List<T> emptyIfNull(@Nullable List<T> cur) { 110 return cur == null ? Collections.emptyList() : cur; 111 } 112 113 /** 114 * Returns the given set, or an immutable empty set if the provided set is null 115 * 116 * This can be used to guarantee null-safety without paying the price of extra allocations 117 * 118 * @see Collections#emptySet 119 */ emptyIfNull(@ullable Set<T> cur)120 public static @NonNull <T> Set<T> emptyIfNull(@Nullable Set<T> cur) { 121 return cur == null ? Collections.emptySet() : cur; 122 } 123 124 /** 125 * Returns the size of the given list, or 0 if the list is null 126 */ size(@ullable Collection<?> cur)127 public static int size(@Nullable Collection<?> cur) { 128 return cur != null ? cur.size() : 0; 129 } 130 131 /** 132 * Returns the elements of the given list that are of type {@code c} 133 */ filter(@ullable List<?> list, Class<T> c)134 public static @NonNull <T> List<T> filter(@Nullable List<?> list, Class<T> c) { 135 if (isEmpty(list)) return Collections.emptyList(); 136 ArrayList<T> result = null; 137 for (int i = 0; i < list.size(); i++) { 138 final Object item = list.get(i); 139 if (c.isInstance(item)) { 140 result = ArrayUtils.add(result, (T) item); 141 } 142 } 143 return emptyIfNull(result); 144 } 145 146 /** 147 * Returns whether there exists at least one element in the list for which 148 * condition {@code predicate} is true 149 */ any(@ullable List<T> items, java.util.function.Predicate<T> predicate)150 public static <T> boolean any(@Nullable List<T> items, 151 java.util.function.Predicate<T> predicate) { 152 return find(items, predicate) != null; 153 } 154 155 /** 156 * Returns the first element from the list for which 157 * condition {@code predicate} is true, or null if there is no such element 158 */ find(@ullable List<T> items, java.util.function.Predicate<T> predicate)159 public static @Nullable <T> T find(@Nullable List<T> items, 160 java.util.function.Predicate<T> predicate) { 161 if (isEmpty(items)) return null; 162 for (int i = 0; i < items.size(); i++) { 163 final T item = items.get(i); 164 if (predicate.test(item)) return item; 165 } 166 return null; 167 } 168 169 /** 170 * Similar to {@link List#add}, but with support for list values of {@code null} and 171 * {@link Collections#emptyList} 172 */ add(@ullable List<T> cur, T val)173 public static @NonNull <T> List<T> add(@Nullable List<T> cur, T val) { 174 if (cur == null || cur == Collections.emptyList()) { 175 cur = new ArrayList<>(); 176 } 177 cur.add(val); 178 return cur; 179 } 180 181 /** 182 * Similar to {@link List#remove}, but with support for list values of {@code null} and 183 * {@link Collections#emptyList} 184 */ remove(@ullable List<T> cur, T val)185 public static @NonNull <T> List<T> remove(@Nullable List<T> cur, T val) { 186 if (isEmpty(cur)) { 187 return emptyIfNull(cur); 188 } 189 cur.remove(val); 190 return cur; 191 } 192 193 /** 194 * @return a list that will not be affected by mutations to the given original list. 195 */ copyOf(@ullable List<T> cur)196 public static @NonNull <T> List<T> copyOf(@Nullable List<T> cur) { 197 return isEmpty(cur) ? Collections.emptyList() : new ArrayList<>(cur); 198 } 199 } 200