org.aksw.commons.collections.utils.StreamUtils Maven / Gradle / Ivy
package org.aksw.commons.collections.utils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.aksw.commons.collections.IteratorUtils;
import org.aksw.commons.lambda.throwing.ThrowingBiConsumer;
import org.aksw.commons.lambda.throwing.ThrowingFunction;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.Streams;
public class StreamUtils {
/**
* Create a single-use {@link Iterable} from a stream. Allows for easier use of Streams in
* for-loops:
*
* {@code
* Stream stream = ...;
* for (T item : StreamUtils.iterableOf(stream)) {
* }
* }
*
* @param
* @param stream
* @return
*/
public static Iterable iterable(Stream stream) {
Iterable result = () -> stream.iterator();
return result;
}
public static T expectOneItem(Stream stream) {
try {
return IteratorUtils.expectOneItem(stream.iterator());
} finally {
stream.close();
}
}
public static T expectZeroOrOneItems(Stream stream) {
try {
return IteratorUtils.expectZeroOrOneItems(stream.iterator());
} finally {
stream.close();
}
}
/**
* Note we could implement another version where each batch's List is lazy loaded from the stream -
* but this would probably require complete consumption of each batch in order
*
* @param stream
* @param batchSize
* @return
*/
public static Stream> mapToBatch(Stream stream, int batchSize) {
Iterator baseIt = stream.iterator();
Iterator> it = new AbstractIterator>() {
@Override
protected List computeNext() {
List items = new ArrayList<>(batchSize);
for(int i = 0; baseIt.hasNext() && i < batchSize; ++i) {
T item = baseIt.next();
items.add(item);
}
List r = items.isEmpty()
? endOfData()
: items;
return r;
}
};
Iterable> tmp = () -> it;
Stream> result = Streams.stream(tmp);
result.onClose(() -> stream.close());
return result;
}
// public static Stream stream(Iterator it) {
// Iterable i = () -> it;
// return stream(i);
// }
//
// public static Stream stream(Iterable i) {
// Stream result = StreamSupport.stream(i.spliterator(), false);
// return result;
// }
/**
* Creates a new stream which upon reaching its end performs and action.
* It concatenates the original stream with one having a single item
* that is filtered out again. The action is run as- part of the filter.
*
* @param stream
* @param runnable
* @return
*/
public static Stream appendAction(Stream extends T> stream, Runnable runnable) {
Stream result = Stream.concat(
stream,
Stream
.of((T)null)
.filter(x -> {
runnable.run();
return false;
})
);
return result;
}
// TODO Add to StreamUtils
public static Stream stream(BiConsumer> fn, S baseSolution) {
List result = new ArrayList<>();
fn.accept(baseSolution, (item) -> result.add(item));
return result.stream();
}
/**
* Creates a stream over a resource via an enumerable.
* The resource is initialized lazily once the first item is read from the stream.
* The returned stream should be used in a try-with-resources block in order
* to close the underlying resource.
*
* @param The record type (e.g. an array of Strings)
* @param The resource type (e.g. a java.sql.Connection)
* @param An enumerable (e.g. a java.sql.ResultSet)
* @param resourceSupplier
* @param toEnumerable
* @param nextRecord
* @param closer
* @return
*/
public static Stream fromEnumerableResource(
Callable resourceSupplier,
ThrowingFunction super R, E> toEnumerable,
ThrowingFunction super E, T> nextRecord,
BiPredicate hasEnded,
ThrowingBiConsumer super R, ? super E> closer) {
IteratorOverEnumerable it = new IteratorOverEnumerable<>(resourceSupplier, toEnumerable, nextRecord, hasEnded, closer);
Stream result = Streams.stream(it).onClose(it::close);
return result;
}
public static class IteratorOverEnumerable
extends AbstractIterator
implements AutoCloseable
{
protected Callable resourceSupplier;
protected ThrowingFunction super R, E> toEnumerable;
protected ThrowingFunction super E, T> nextRecord;
protected BiPredicate hasEnded;
protected ThrowingBiConsumer super R, ? super E> closer;
protected boolean isClosed = false;
protected R resource;
protected E enumerable;
public IteratorOverEnumerable(
Callable resourceSupplier,
ThrowingFunction super R, E> toEnumerable,
ThrowingFunction super E, T> nextRecord,
BiPredicate hasEnded,
ThrowingBiConsumer super R, ? super E> closer) {
this.resourceSupplier = resourceSupplier;
this.toEnumerable = toEnumerable;
this.nextRecord = nextRecord;
this.hasEnded = hasEnded;
this.closer = closer;
}
@Override
protected T computeNext() {
if (isClosed) {
throw new IllegalStateException("already closed");
}
if (enumerable == null) {
try {
if (resource == null) {
resource = resourceSupplier.call();
}
enumerable = toEnumerable.apply(resource);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
T result;
try {
result = nextRecord.apply(enumerable);
} catch (Exception e) {
throw new RuntimeException(e);
}
boolean isDone = hasEnded.test(result, enumerable);
if (isDone) {
result = endOfData();
}
return result;
}
@Override
public void close() {
isClosed = true;
try {
if (resource != null) {
closer.accept(resource, enumerable);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public static Stream viaList(Stream in, Consumer> consumer) {
List list;
try (Stream tmp = in) {
list = tmp.collect(Collectors.toList());
}
if (consumer != null) {
consumer.accept(list);
}
return list.stream();
}
public static Stream println(Stream in) {
return viaList(in, System.out::println);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy