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