CollectionUtils.java revision 6a7006a9683ba5a79ca338050c7c50b346b04de0
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 android.annotation.NonNull;
20import android.annotation.Nullable;
21
22import java.util.ArrayList;
23import java.util.Collection;
24import java.util.Collections;
25import java.util.List;
26import java.util.function.Function;
27import java.util.stream.Stream;
28
29/**
30 * Utility methods for dealing with (typically {@link Nullable}) {@link Collection}s
31 *
32 * Unless a method specifies otherwise, a null value for a collection is treated as an empty
33 * collection of that type.
34 */
35public class CollectionUtils {
36    private CollectionUtils() { /* cannot be instantiated */ }
37
38    /**
39     * Returns a list of items from the provided list that match the given condition.
40     *
41     * This is similar to {@link Stream#filter} but without the overhead of creating an intermediate
42     * {@link Stream} instance
43     */
44    public static @NonNull <T> List<T> filter(@Nullable List<T> list,
45            java.util.function.Predicate<? super T> predicate) {
46        ArrayList<T> result = null;
47        for (int i = 0; i < size(list); i++) {
48            final T item = list.get(i);
49            if (predicate.test(item)) {
50                result = ArrayUtils.add(result, item);
51            }
52        }
53        return emptyIfNull(result);
54    }
55
56    /**
57     * Returns a list of items resulting from applying the given function to each element of the
58     * provided list.
59     *
60     * The resulting list will have the same {@link #size} as the input one.
61     *
62     * This is similar to {@link Stream#map} but without the overhead of creating an intermediate
63     * {@link Stream} instance
64     */
65    public static @NonNull <I, O> List<O> map(@Nullable List<I> cur,
66            Function<? super I, ? extends O> f) {
67        if (cur == null || cur.isEmpty()) return Collections.emptyList();
68        final ArrayList<O> result = new ArrayList<>();
69        for (int i = 0; i < cur.size(); i++) {
70            result.add(f.apply(cur.get(i)));
71        }
72        return result;
73    }
74
75    /**
76     * Returns the given list, or an immutable empty list if the provided list is null
77     *
78     * This can be used to guaranty null-safety without paying the price of extra allocations
79     *
80     * @see Collections#emptyList
81     */
82    public static @NonNull <T> List<T> emptyIfNull(@Nullable List<T> cur) {
83        return cur == null ? Collections.emptyList() : cur;
84    }
85
86    /**
87     * Returns the size of the given list, or 0 if the list is null
88     */
89    public static int size(@Nullable Collection<?> cur) {
90        return cur != null ? cur.size() : 0;
91    }
92
93    /**
94     * Returns the elements of the given list that are of type {@code c}
95     */
96    public static @NonNull <T> List<T> filter(@Nullable List<?> list, Class<T> c) {
97        if (ArrayUtils.isEmpty(list)) return Collections.emptyList();
98        ArrayList<T> result = null;
99        for (int i = 0; i < list.size(); i++) {
100            final Object item = list.get(i);
101            if (c.isInstance(item)) {
102                result = ArrayUtils.add(result, (T) item);
103            }
104        }
105        return emptyIfNull(result);
106    }
107
108    /**
109     * Returns whether there exists at least one element in the list for which
110     * condition {@code predicate} is true
111     */
112    public static <T> boolean any(@Nullable List<T> items,
113            java.util.function.Predicate<T> predicate) {
114        return find(items, predicate) != null;
115    }
116
117    /**
118     * Returns the first element from the list for which
119     * condition {@code predicate} is true, or null if there is no such element
120     */
121    public static @Nullable <T> T find(@Nullable List<T> items,
122            java.util.function.Predicate<T> predicate) {
123        if (ArrayUtils.isEmpty(items)) return null;
124        for (int i = 0; i < items.size(); i++) {
125            final T item = items.get(i);
126            if (predicate.test(item)) return item;
127        }
128        return null;
129    }
130}
131