001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.internal; 018 019import static org.apache.juneau.common.utils.Utils.*; 020 021import java.lang.reflect.*; 022import java.util.*; 023 024import org.apache.juneau.common.utils.*; 025 026/** 027 * Quick and dirty utilities for working with arrays. 028 * 029 * <h5 class='section'>See Also:</h5><ul> 030 031 * </ul> 032 */ 033public class ArrayUtils { 034 035 /** 036 * Appends one or more elements to an array. 037 * 038 * @param <T> The element type. 039 * @param array The array to append to. 040 * @param newElements The new elements to append to the array. 041 * @return A new array with the specified elements appended. 042 */ 043 @SuppressWarnings("unchecked") 044 public static <T> T[] append(T[] array, T...newElements) { 045 if (array == null) 046 return newElements; 047 if (newElements.length == 0) 048 return array; 049 T[] a = (T[])Array.newInstance(array.getClass().getComponentType(), array.length + newElements.length); 050 for (int i = 0; i < array.length; i++) 051 a[i] = array[i]; 052 for (int i = 0; i < newElements.length; i++) 053 a[i+array.length] = newElements[i]; 054 return a; 055 } 056 057 /** 058 * Combine an arbitrary number of arrays into a single array. 059 * 060 * @param <E> The element type. 061 * @param arrays Collection of arrays to combine. 062 * @return A new combined array, or <jk>null</jk> if all arrays are <jk>null</jk>. 063 */ 064 @SuppressWarnings("unchecked") 065 public static <E> E[] combine(E[]...arrays) { 066 Utils.assertArgNotNull("arrays", arrays); 067 int l = 0; 068 E[] a1 = null; 069 for (E[] a : arrays) { 070 if (a1 == null && a != null) 071 a1 = a; 072 l += (a == null ? 0 : a.length); 073 } 074 if (a1 == null) 075 return null; 076 E[] a = (E[])Array.newInstance(a1.getClass().getComponentType(), l); 077 int i = 0; 078 for (E[] aa : arrays) 079 if (aa != null) 080 for (E t : aa) 081 a[i++] = t; 082 return a; 083 } 084 085 /** 086 * Converts the specified array to a <c>Set</c>. 087 * 088 * <p> 089 * The order of the entries in the set are the same as the array. 090 * 091 * @param <T> The entry type of the array. 092 * @param array The array being wrapped in a <c>Set</c> interface. 093 * @return The new set. 094 */ 095 public static <T> Set<T> asSet(final T[] array) { 096 Utils.assertArgNotNull("array", array); 097 return new AbstractSet<>() { 098 099 @Override /* Set */ 100 public Iterator<T> iterator() { 101 return new Iterator<>() { 102 int i = 0; 103 104 @Override /* Iterator */ 105 public boolean hasNext() { 106 return i < array.length; 107 } 108 109 @Override /* Iterator */ 110 public T next() { 111 if (i >= array.length) 112 throw new NoSuchElementException(); 113 T t = array[i]; 114 i++; 115 return t; 116 } 117 118 @Override /* Iterator */ 119 public void remove() { 120 throw new UnsupportedOperationException("Not supported."); 121 } 122 }; 123 } 124 125 @Override /* Set */ 126 public int size() { 127 return array.length; 128 } 129 }; 130 } 131 132 /** 133 * Converts the specified collection to an array. 134 * 135 * <p> 136 * Works on both object and primitive arrays. 137 * 138 * @param <E> The element type. 139 * @param c The collection to convert to an array. 140 * @param elementType The component type of the collection. 141 * @return A new array. 142 */ 143 public static <E> Object toArray(Collection<?> c, Class<E> elementType) { 144 Object a = Array.newInstance(elementType, c.size()); 145 Iterator<?> it = c.iterator(); 146 int i = 0; 147 while (it.hasNext()) 148 Array.set(a, i++, it.next()); 149 return a; 150 } 151 152 /** 153 * Converts the specified array to an <c>ArrayList</c> 154 * 155 * @param <E> The element type. 156 * @param array The array to convert. 157 * @param elementType 158 * The type of objects in the array. 159 * It must match the actual component type in the array. 160 * @return A new {@link ArrayList} 161 */ 162 @SuppressWarnings("unchecked") 163 public static <E> List<E> toList(Object array, Class<E> elementType) { 164 List<E> l = new ArrayList<>(Array.getLength(array)); 165 for (int i = 0; i < Array.getLength(array); i++) 166 l.add((E)Array.get(array, i)); 167 return l; 168 } 169 170 /** 171 * Recursively converts the specified array into a list of objects. 172 * 173 * @param array The array to convert. 174 * @return A new {@link ArrayList} 175 */ 176 public static List<Object> toObjectList(Object array) { 177 List<Object> l = new ArrayList<>(Array.getLength(array)); 178 for (int i = 0; i < Array.getLength(array); i++) { 179 Object o = Array.get(array, i); 180 if (isArray(o)) 181 o = toObjectList(o); 182 l.add(o); 183 } 184 return l; 185 } 186 187 /** 188 * Copies the specified array into the specified list. 189 * 190 * <p> 191 * Works on both object and primitive arrays. 192 * 193 * @param array The array to copy into a list. 194 * @param list The list to copy the values into. 195 * @return The same list passed in. 196 */ 197 @SuppressWarnings({"unchecked","rawtypes"}) 198 public static List copyToList(Object array, List list) { 199 if (array != null) { 200 int length = Array.getLength(array); 201 for (int i = 0; i < length; i++) 202 list.add(Array.get(array, i)); 203 } 204 return list; 205 } 206 207 /** 208 * Returns <jk>true</jk> if the specified array contains the specified element using the {@link String#equals(Object)} 209 * method. 210 * 211 * @param element The element to check for. 212 * @param array The array to check. 213 * @return 214 * <jk>true</jk> if the specified array contains the specified element, 215 * <jk>false</jk> if the array or element is <jk>null</jk>. 216 */ 217 public static boolean contains(String element, String[] array) { 218 return indexOf(element, array) != -1; 219 } 220 221 /** 222 * Returns the index position of the element in the specified array using the {@link String#equals(Object)} method. 223 * 224 * @param element The element to check for. 225 * @param array The array to check. 226 * @return 227 * The index position of the element in the specified array, or 228 * <c>-1</c> if the array doesn't contain the element, or the array or element is <jk>null</jk>. 229 */ 230 public static int indexOf(String element, String[] array) { 231 if (element == null || array == null) 232 return -1; 233 for (int i = 0; i < array.length; i++) 234 if (element.equals(array[i])) 235 return i; 236 return -1; 237 } 238 239 /** 240 * Converts the specified collection to an array of strings. 241 * 242 * <p> 243 * Entries are converted to strings using {@link #toString()}. 244 * <jk>null</jk> values remain <jk>null</jk>. 245 * 246 * @param c The collection to convert. 247 * @return The collection as a string array. 248 */ 249 public static String[] toStringArray(Collection<?> c) { 250 String[] r = new String[c.size()]; 251 int i = 0; 252 for (Object o : c) 253 r[i++] = Utils.s(o); 254 return r; 255 } 256 257 /** 258 * Returns <jk>true</jk> if the following sorted arrays are equals. 259 * 260 * @param a1 Array #1. 261 * @param a2 Array #2. 262 * @return <jk>true</jk> if the following sorted arrays are equals. 263 */ 264 public static boolean equals(String[] a1, String[] a2) { 265 if (a1.length != a2.length) 266 return false; 267 for (int i = 0; i < a1.length; i++) 268 if (! Utils.eq(a1[i], a2[i])) 269 return false; 270 return true; 271 } 272 273 /** 274 * Makes a copy of the specified array. 275 * 276 * @param array The array to copy. 277 * @param <T> The element type. 278 * @return A new copy of the array, or <jk>null</jk> if the array was <jk>null</jk>.s 279 */ 280 public static <T> T[] copyOf(T[] array) { 281 return array == null ? null : Arrays.copyOf(array, array.length); 282 } 283 284 /** 285 * Returns <jk>true</jk> if the specified array is not null and has a length greater than zero. 286 * 287 * @param array The array to check. 288 * @return <jk>true</jk> if the specified array is not null and has a length greater than zero. 289 */ 290 public static boolean isNotEmptyArray(Object[] array) { 291 return array != null && array.length > 0; 292 } 293 294 /** 295 * Returns <jk>true</jk> if the specified array is null or has a length of zero. 296 * 297 * @param array The array to check. 298 * @return <jk>true</jk> if the specified array is null or has a length of zero. 299 */ 300 public static boolean isEmptyArray(Object[] array) { 301 return array == null || array.length == 0; 302 } 303 304 /** 305 * Returns <jk>true</jk> if both specified arrays are null or have a length of zero. 306 * 307 * @param array1 The array to check. 308 * @param array2 The array to check. 309 * @return <jk>true</jk> if the specified array is null or has a length of zero. 310 */ 311 public static boolean isEmptyArray(Object[] array1, Object[] array2) { 312 return isEmptyArray(array1) && isEmptyArray(array2); 313 } 314 315 /** 316 * Reverses the entries in an array. 317 * 318 * @param <E> The element type. 319 * @param array The array to reverse. 320 * @return The same array. 321 */ 322 public static <E> E[] reverse(E[] array) { 323 for (int i = 0; i < array.length / 2; i++) { 324 E temp = array[i]; 325 array[i] = array[array.length - i - 1]; 326 array[array.length - i - 1] = temp; 327 } 328 return array; 329 } 330}