HADOOP-17152. Provide Hadoop's own Lists utility to reduce dependency on Guava (#3061)
Change-Id: I52e55b9d9826ad661e9ad7dc15f007aa168f0fe1 Reviewed-by: Wei-Chiu Chuang <weichiu@apache.org> Signed-off-by: Takanobu Asanuma <tasanuma@apache.org>
This commit is contained in:
parent
6c58f83b78
commit
5e9e779ed2
|
@ -0,0 +1,235 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.hadoop.util;
|
||||||
|
|
||||||
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static utility methods pertaining to {@link List} instances.
|
||||||
|
* This class is Hadoop's internal use alternative to Guava's Lists
|
||||||
|
* utility class.
|
||||||
|
* Javadocs for majority of APIs in this class are taken from Guava's Lists
|
||||||
|
* class from Guava release version 27.0-jre.
|
||||||
|
*/
|
||||||
|
@InterfaceAudience.Private
|
||||||
|
public final class Lists {
|
||||||
|
|
||||||
|
private Lists() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a <i>mutable</i>, empty {@code ArrayList} instance.
|
||||||
|
*/
|
||||||
|
public static <E> ArrayList<E> newArrayList() {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a <i>mutable</i> {@code ArrayList} instance containing the given
|
||||||
|
* elements.
|
||||||
|
*
|
||||||
|
* <p>Note that even when you do need the ability to add or remove,
|
||||||
|
* this method provides only a tiny bit of syntactic sugar for
|
||||||
|
* {@code newArrayList(}
|
||||||
|
* {@link Arrays#asList asList}
|
||||||
|
* {@code (...))}, or for creating an empty list then calling
|
||||||
|
* {@link Collections#addAll}.
|
||||||
|
*/
|
||||||
|
@SafeVarargs
|
||||||
|
public static <E> ArrayList<E> newArrayList(E... elements) {
|
||||||
|
if (elements == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
// Avoid integer overflow when a large array is passed in
|
||||||
|
int capacity = computeArrayListCapacity(elements.length);
|
||||||
|
ArrayList<E> list = new ArrayList<>(capacity);
|
||||||
|
Collections.addAll(list, elements);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a <i>mutable</i> {@code ArrayList} instance containing the
|
||||||
|
* given elements; a very thin shortcut for creating an empty list then
|
||||||
|
* calling Iterables#addAll.
|
||||||
|
*/
|
||||||
|
public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
|
||||||
|
if (elements == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
return (elements instanceof Collection)
|
||||||
|
? new ArrayList<>(cast(elements))
|
||||||
|
: newArrayList(elements.iterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a <i>mutable</i> {@code ArrayList} instance containing the
|
||||||
|
* given elements; a very thin shortcut for creating an empty list
|
||||||
|
* and then calling Iterators#addAll.
|
||||||
|
*/
|
||||||
|
public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements) {
|
||||||
|
ArrayList<E> list = newArrayList();
|
||||||
|
addAll(list, elements);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an {@code ArrayList} instance backed by an array with the
|
||||||
|
* specified initial size;
|
||||||
|
* simply delegates to {@link ArrayList#ArrayList(int)}.
|
||||||
|
*
|
||||||
|
* @param initialArraySize the exact size of the initial backing array for
|
||||||
|
* the returned array list
|
||||||
|
* ({@code ArrayList} documentation calls this value the "capacity").
|
||||||
|
* @return a new, empty {@code ArrayList} which is guaranteed not to
|
||||||
|
* resize itself unless its size reaches {@code initialArraySize + 1}.
|
||||||
|
* @throws IllegalArgumentException if {@code initialArraySize} is negative.
|
||||||
|
*/
|
||||||
|
public static <E> ArrayList<E> newArrayListWithCapacity(
|
||||||
|
int initialArraySize) {
|
||||||
|
checkNonnegative(initialArraySize, "initialArraySize");
|
||||||
|
return new ArrayList<>(initialArraySize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an {@code ArrayList} instance to hold {@code estimatedSize}
|
||||||
|
* elements, <i>plus</i> an unspecified amount of padding;
|
||||||
|
* you almost certainly mean to call {@link
|
||||||
|
* #newArrayListWithCapacity} (see that method for further advice on usage).
|
||||||
|
*
|
||||||
|
* @param estimatedSize an estimate of the eventual {@link List#size()}
|
||||||
|
* of the new list.
|
||||||
|
* @return a new, empty {@code ArrayList}, sized appropriately to hold the
|
||||||
|
* estimated number of elements.
|
||||||
|
* @throws IllegalArgumentException if {@code estimatedSize} is negative.
|
||||||
|
*/
|
||||||
|
public static <E> ArrayList<E> newArrayListWithExpectedSize(
|
||||||
|
int estimatedSize) {
|
||||||
|
return new ArrayList<>(computeArrayListCapacity(estimatedSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a <i>mutable</i>, empty {@code LinkedList} instance.
|
||||||
|
*
|
||||||
|
* <p><b>Performance note:</b> {@link ArrayList} and
|
||||||
|
* {@link java.util.ArrayDeque} consistently
|
||||||
|
* outperform {@code LinkedList} except in certain rare and specific
|
||||||
|
* situations. Unless you have
|
||||||
|
* spent a lot of time benchmarking your specific needs, use one of those
|
||||||
|
* instead.
|
||||||
|
*/
|
||||||
|
public static <E> LinkedList<E> newLinkedList() {
|
||||||
|
return new LinkedList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a <i>mutable</i> {@code LinkedList} instance containing the given
|
||||||
|
* elements; a very thin shortcut for creating an empty list then calling
|
||||||
|
* Iterables#addAll.
|
||||||
|
*
|
||||||
|
* <p><b>Performance note:</b> {@link ArrayList} and
|
||||||
|
* {@link java.util.ArrayDeque} consistently
|
||||||
|
* outperform {@code LinkedList} except in certain rare and specific
|
||||||
|
* situations. Unless you have spent a lot of time benchmarking your
|
||||||
|
* specific needs, use one of those instead.
|
||||||
|
*/
|
||||||
|
public static <E> LinkedList<E> newLinkedList(
|
||||||
|
Iterable<? extends E> elements) {
|
||||||
|
LinkedList<E> list = newLinkedList();
|
||||||
|
addAll(list, elements);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int computeArrayListCapacity(int arraySize) {
|
||||||
|
checkNonnegative(arraySize, "arraySize");
|
||||||
|
return saturatedCast(5L + arraySize + (arraySize / 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int checkNonnegative(int value, String name) {
|
||||||
|
if (value < 0) {
|
||||||
|
throw new IllegalArgumentException(name + " cannot be negative but was: "
|
||||||
|
+ value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@code int} nearest in value to {@code value}.
|
||||||
|
*
|
||||||
|
* @param value any {@code long} value.
|
||||||
|
* @return the same value cast to {@code int} if it is in the range of the
|
||||||
|
* {@code int} type, {@link Integer#MAX_VALUE} if it is too large,
|
||||||
|
* or {@link Integer#MIN_VALUE} if it is too small.
|
||||||
|
*/
|
||||||
|
private static int saturatedCast(long value) {
|
||||||
|
if (value > Integer.MAX_VALUE) {
|
||||||
|
return Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
if (value < Integer.MIN_VALUE) {
|
||||||
|
return Integer.MIN_VALUE;
|
||||||
|
}
|
||||||
|
return (int) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> boolean addAll(Collection<T> addTo,
|
||||||
|
Iterator<? extends T> iterator) {
|
||||||
|
if (addTo == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
if (iterator == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
boolean wasModified = false;
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
wasModified |= addTo.add(iterator.next());
|
||||||
|
}
|
||||||
|
return wasModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> Collection<T> cast(Iterable<T> iterable) {
|
||||||
|
return (Collection<T>) iterable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds all elements in {@code iterable} to {@code collection}.
|
||||||
|
*
|
||||||
|
* @return {@code true} if {@code collection} was modified as a result of
|
||||||
|
* this operation.
|
||||||
|
*/
|
||||||
|
private static <T> boolean addAll(Collection<T> addTo,
|
||||||
|
Iterable<? extends T> elementsToAdd) {
|
||||||
|
if (elementsToAdd instanceof Collection) {
|
||||||
|
Collection<? extends T> c = cast(elementsToAdd);
|
||||||
|
return addTo.addAll(c);
|
||||||
|
}
|
||||||
|
if (elementsToAdd == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
return addAll(addTo, elementsToAdd.iterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.hadoop.util;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple tests for utility class Lists.
|
||||||
|
*/
|
||||||
|
public class TestLists {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddToEmptyArrayList() {
|
||||||
|
List<String> list = Lists.newArrayList();
|
||||||
|
list.add("record1");
|
||||||
|
Assert.assertEquals(1, list.size());
|
||||||
|
Assert.assertEquals("record1", list.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddToEmptyLinkedList() {
|
||||||
|
List<String> list = Lists.newLinkedList();
|
||||||
|
list.add("record1");
|
||||||
|
Assert.assertEquals(1, list.size());
|
||||||
|
Assert.assertEquals("record1", list.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVarArgArrayLists() {
|
||||||
|
List<String> list = Lists.newArrayList("record1", "record2", "record3");
|
||||||
|
list.add("record4");
|
||||||
|
Assert.assertEquals(4, list.size());
|
||||||
|
Assert.assertEquals("record1", list.get(0));
|
||||||
|
Assert.assertEquals("record2", list.get(1));
|
||||||
|
Assert.assertEquals("record3", list.get(2));
|
||||||
|
Assert.assertEquals("record4", list.get(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testItrArrayLists() {
|
||||||
|
Set<String> set = new HashSet<>();
|
||||||
|
set.add("record1");
|
||||||
|
set.add("record2");
|
||||||
|
set.add("record3");
|
||||||
|
List<String> list = Lists.newArrayList(set);
|
||||||
|
list.add("record4");
|
||||||
|
Assert.assertEquals(4, list.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testItrLinkedLists() {
|
||||||
|
Set<String> set = new HashSet<>();
|
||||||
|
set.add("record1");
|
||||||
|
set.add("record2");
|
||||||
|
set.add("record3");
|
||||||
|
List<String> list = Lists.newLinkedList(set);
|
||||||
|
list.add("record4");
|
||||||
|
Assert.assertEquals(4, list.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testArrayListWithSize() {
|
||||||
|
List<String> list = Lists.newArrayListWithCapacity(3);
|
||||||
|
list.add("record1");
|
||||||
|
list.add("record2");
|
||||||
|
list.add("record3");
|
||||||
|
Assert.assertEquals(3, list.size());
|
||||||
|
Assert.assertEquals("record1", list.get(0));
|
||||||
|
Assert.assertEquals("record2", list.get(1));
|
||||||
|
Assert.assertEquals("record3", list.get(2));
|
||||||
|
list = Lists.newArrayListWithCapacity(3);
|
||||||
|
list.add("record1");
|
||||||
|
list.add("record2");
|
||||||
|
list.add("record3");
|
||||||
|
Assert.assertEquals(3, list.size());
|
||||||
|
Assert.assertEquals("record1", list.get(0));
|
||||||
|
Assert.assertEquals("record2", list.get(1));
|
||||||
|
Assert.assertEquals("record3", list.get(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue