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