com.github.scr.j8iterables.J8Iterables Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of j8iterables Show documentation
Show all versions of j8iterables Show documentation
Extension of Guava Iterables using Java 8 Collections and Streams
package com.github.scr.j8iterables;
import com.github.scr.j8iterables.core.ConsumingIdentity;
import com.github.scr.j8iterables.core.StreamIterable;
import com.google.common.collect.FluentIterable;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Optional;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* Utility methods to extend Guava Iterables with Java 8 Stream-like classes such as Collectors.
*
* @author scr
*/
public class J8Iterables {
/**
* Collect iterable of iterables into a mutable container.
*
* @param iterables The iterable of iterables
* @param supplier The container supplier
* @param accumulator The accumulator function
* @param combiner The combiner function
* @param The type of elements
* @param The return type
* @return Collected result
* @see Stream#collect(Supplier, BiConsumer, BiConsumer)
*/
public static R collect(@NotNull Iterable> iterables,
@NotNull Supplier supplier,
@NotNull BiConsumer accumulator,
@NotNull BiConsumer combiner) {
R result = supplier.get();
for (Iterable iterable : iterables) {
R innerResult = supplier.get();
for (T element : iterable) {
accumulator.accept(innerResult, element);
}
combiner.accept(result, innerResult);
}
return result;
}
/**
* Collect iterable into a mutable container.
*
* @param iterable The iterable
* @param collector The collector object
* @param The type of elements
* @param The type of accumulator
* @param The return type
* @return Collected result
* @see Stream#collect(Collector)
*/
public static R collect(@NotNull Iterable iterable, @NotNull Collector super T, A, R> collector) {
A container = collector.supplier().get();
BiConsumer accumulator = collector.accumulator();
for (T t : iterable) {
accumulator.accept(container, t);
}
return collector.finisher().apply(container);
}
/**
* Perform a reduction on iterable.
*
* @param iterable The iterable
* @param accumulator The accumulator function
* @param The type of elements
* @return The reduced result
* @see Stream#reduce(BinaryOperator)
*/
public static Optional reduce(@NotNull Iterable iterable, @NotNull BinaryOperator accumulator) {
boolean foundAny = false;
T result = null;
for (T element : iterable) {
if (!foundAny) {
foundAny = true;
result = element;
} else {
result = accumulator.apply(result, element);
}
}
return foundAny ? Optional.of(result) : Optional.empty();
}
/**
* Perform a reduction on an iterable.
*
* @param iterable The iterable
* @param identity The identity to start reduction with
* @param accumulator The accumulator function
* @param The type of elements
* @return The reduced result
* @see Stream#reduce(Object, BinaryOperator)
*/
public static T reduce(@NotNull Iterable iterable,
T identity,
@NotNull BinaryOperator accumulator) {
T result = identity;
for (T element : iterable) {
result = accumulator.apply(result, element);
}
return result;
}
/**
* Perform a reduction on an iterable of iterables.
*
* @param iterables An iterator of iterables.
* @param identity The identity to start reduction with
* @param accumulator The accumulator function
* @param combiner The combiner function
* @param The type of elements
* @param The reduced type
* @return The reduced result
* @see Stream#reduce(Object, BiFunction, BinaryOperator)
*/
public static U reduce(@NotNull Iterable> iterables,
U identity,
@NotNull BiFunction accumulator,
@NotNull BinaryOperator combiner) {
U result = identity;
for (Iterable iterable : iterables) {
U innerResult = identity;
for (T element : iterable) {
innerResult = accumulator.apply(innerResult, element);
}
result = combiner.apply(result, innerResult);
}
return result;
}
/**
* Peek at the iterable without modifying the result.
*
* @param iterable The iterable to peek at
* @param consumer The peeking function
* @param The type of elements
* @return an Iterable that, when traversed will invoke the consumer on each element
* @see Stream#peek(Consumer)
*/
@NotNull
public static FluentIterable peek(@NotNull Iterable iterable, @NotNull Consumer consumer) {
return FluentIterable.from(iterable).transform(peeker(consumer));
}
/**
* Return a peeking transformer - a UnaryOperator that will send each element to the consumer and return identity.
*
* @param consumer The peeking function
* @param The type of elements
* @return a peeking (non-transforming) transformer
*/
@NotNull
public static ConsumingIdentity peeker(@NotNull Consumer consumer) {
return new ConsumingIdentity<>(consumer);
}
/**
* Create a one-time Iterable from a Stream.
*
* @param stream The Stream to use in creating an Iterable
* @param The type of elements
* @return Iterable from the given stream
*/
@NotNull
public static FluentIterable fromStream(@NotNull Stream stream) {
return new StreamIterable<>(stream);
}
/**
* Create a Stream from the given Iterable.
*
* @param iterable The Iterable to use in creating a Stream
* @param The type of elements
* @return Stream from the given iterable
*/
@NotNull
public static Stream toStream(@NotNull Iterable iterable) {
if (iterable instanceof Collection) {
return ((Collection) iterable).stream();
}
// TODO(scr): Is it possible to do late-binding (iterable::spliterator)? Need to know characteristics.
return StreamSupport.stream(iterable.spliterator(), false);
}
}