apoc.util.collection.Iterables Maven / Gradle / Ivy
Show all versions of apoc-common Show documentation
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed 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 apoc.util.collection;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;
import org.neo4j.graphdb.Resource;
import org.neo4j.graphdb.ResourceIterable;
import org.neo4j.graphdb.ResourceIterator;
/**
* Utility methods for processing iterables. Where possible, If the iterable implements
* {@link Resource}, it will be {@link Resource#close() closed} when the processing
* has been completed.
*/
public final class Iterables {
/**
* Collect all the elements available in {@code iterable} and add them to the
* provided {@code collection}.
*
* If the {@code iterable} implements {@link Resource} it will be
* {@link Resource#close() closed} in a {@code finally} block after all
* the items have been added.
*
* @param collection the collection to add items to.
* @param iterable the iterable from which items will be collected
* @param the type of elements in {@code iterable}.
* @param the type of the collection to add the items to.
* @return the {@code collection} that has been updated.
*/
public static > C addAll(C collection, Iterable extends T> iterable) {
try {
Iterator extends T> iterator = iterable.iterator();
try {
while (iterator.hasNext()) {
collection.add(iterator.next());
}
} finally {
Iterators.tryCloseResource(iterator);
}
} finally {
tryCloseResource(iterable);
}
return collection;
}
@SafeVarargs
public static Iterable iterable(C... items) {
return Arrays.asList(items);
}
@SuppressWarnings("unchecked")
public static T[] asArray(Class componentType, Iterable iterable) {
if (iterable == null) {
return null;
}
List list = asList(iterable);
return list.toArray((T[]) Array.newInstance(componentType, list.size()));
}
public static ResourceIterable asResourceIterable(final Iterable iterable) {
if (iterable instanceof ResourceIterable>) {
return (ResourceIterable) iterable;
}
return new AbstractResourceIterable<>() {
@Override
protected ResourceIterator newIterator() {
return Iterators.asResourceIterator(iterable.iterator());
}
@Override
protected void onClosed() {
tryCloseResource(iterable);
}
};
}
/**
* Returns the given iterable's first element or {@code null} if no
* element found.
*
* If the {@code iterable} implements {@link Resource}, then it will be closed in a {@code finally} block
* after the first item has been retrieved, or failed to be retrieved.
*
* If the {@link Iterable#iterator() iterator} created by the {@code iterable} implements {@link Resource}
* it will be {@link Resource#close() closed} in a {@code finally} block after the single item
* has been retrieved, or failed to be retrieved.
*
* @param the type of elements in {@code iterable}.
* @param iterable the {@link Iterable} to get elements from.
* @return the first element in the {@code iterable}, or {@code null} if no
* element found.
*/
public static T firstOrNull(Iterable iterable) {
try {
return Iterators.firstOrNull(iterable.iterator());
} finally {
tryCloseResource(iterable);
}
}
/**
* Returns the given iterable's first element. If no element is found a
* {@link NoSuchElementException} is thrown.
*
* If the {@code iterable} implements {@link Resource}, then it will be closed in a {@code finally} block
* after the first item has been retrieved, or failed to be retrieved.
*
* @param the type of elements in {@code iterable}.
* @param iterable the {@link Iterable} to get elements from.
* @return the first element in the {@code iterable}.
* @throws NoSuchElementException if no element found.
*/
public static T first(Iterable iterable) {
try {
return Iterators.first(iterable.iterator());
} finally {
tryCloseResource(iterable);
}
}
/**
* Returns the given iterable's single element. If there are no elements
* or more than one element in the iterable a {@link NoSuchElementException}
* will be thrown.
*
* If the {@code iterable} implements {@link Resource}, then it will be closed in a {@code finally} block
* after the single item has been retrieved, or failed to be retrieved.
*
* If the {@link Iterable#iterator() iterator} created by the {@code iterable} implements {@link Resource}
* it will be {@link Resource#close() closed} in a {@code finally} block after the single item
* has been retrieved, or failed to be retrieved.
*
* @param the type of elements in {@code iterable}.
* @param iterable the {@link Iterable} to get elements from.
* @return the single element in the {@code iterable}.
* @throws NoSuchElementException if there isn't exactly one element.
*/
public static T single(Iterable iterable) {
try {
return Iterators.single(iterable.iterator());
} finally {
tryCloseResource(iterable);
}
}
/**
* Counts the number of items in the {@code iterable} by looping through it.
*
* If the {@code iterable} implements {@link Resource}, then it will be closed in a {@code finally} block
* after all its items have been counted.
*
* If the {@link Iterable#iterator() iterator} created by the {@code iterable} implements {@link Resource}
* it will be {@link Resource#close() closed} in a {@code finally} block after the items have been counted.
*
* @param the type of items in the iterator.
* @param iterable the {@link Iterable} to count items in.
* @return the number of items found in {@code iterable}.
*/
public static long count(Iterable iterable) {
try {
return Iterators.count(iterable.iterator());
} finally {
tryCloseResource(iterable);
}
}
/**
* Creates a list from an iterable.
*
* If the {@code iterable} implements {@link Resource}, then it will be closed in a {@code finally} block
* after all its items have been added.
*
* If the {@link Iterable#iterator() iterator} created by the {@code iterable} implements {@link Resource}
* it will be {@link Resource#close() closed} in a {@code finally} block after all the items have been added.
*
* @param iterable The iterable to create the list from.
* @param The generic type of both the iterable and the list.
* @return a list containing all items from the iterable.
*/
public static List asList(Iterable iterable) {
return addAll(new ArrayList<>(), iterable);
}
/**
* Creates a {@link Set} from an {@link Iterable}.
*
* If the {@code iterable} implements {@link Resource}, then it will be closed in a {@code finally} block
* after all its items have been added.
*
* If the {@link Iterable#iterator() iterator} created by the {@code iterable} implements {@link Resource}
* it will be {@link Resource#close() closed} in a {@code finally} block after all the items have been added.
*
* @param iterable The items to create the set from.
* @param The generic type of items.
* @return a set containing all items from the {@link Iterable}.
*/
public static Set asSet(Iterable iterable) {
return addAll(new HashSet<>(), iterable);
}
/**
* Create a stream from the given iterable.
*
* Note: returned stream needs to be closed via {@link Stream#close()} if the given iterable implements
* {@link Resource}.
*
* @param iterable the iterable to convert to stream
* @param the type of elements in the given iterable
* @return stream over the iterable elements
* @throws NullPointerException when the given iterable is {@code null}
*/
public static Stream stream(Iterable iterable) {
Objects.requireNonNull(iterable);
return Iterators.stream(iterable.iterator()).onClose(() -> tryCloseResource(iterable));
}
/**
* Close the provided {@code iterable} if it implements {@link Resource}.
*
* @param iterable the iterable to check for closing
*/
private static void tryCloseResource(Iterable> iterable) {
if (iterable instanceof Resource closeable) {
closeable.close();
}
}
}