package ch.claude_martin.common;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import ch.claude_martin.common.ToOptional.Ref;
/**
* Collects a single element from a stream into an {@link Optional}. The returned Optional is empty if
* there is not exactly one element in the stream.
*
* <p>
* This is an alternative to {@link Stream#findAny()} as it checks that there is exactly one element
* in the stream that can be <i>found</i>. It can also be seen as an alternative to the
* {@link Collectors}, as this uses an Optional like a {@link Collection}, similar to
* {@link Collectors#toList()}.
* </p>
*
* <p>
* Note that this might take a long time for streams with many elements.
* </p>
*
* <pre>
* Example:
* List<Integer> list = Arrays.asList(1,2,3,4);
* Optional<Integer> o = list.stream().filter(i->i==3).collect(ToOptional.get());
* System.out.println(o); // Optional[3]
* o = list.stream().filter(i->i>0).collect(ToOptional.get());
* System.out.println(o); // Optional.empty
* </pre>
*
* @see Collectors
* @param <T>
* Type of the expected element.
*/
public final class ToOptional<T> implements Collector<T, Ref<T>, Optional<T>> {
private ToOptional() {
super();
}
public final static ToOptional<?> INSTANCE = new ToOptional<>();
/**
* Returns an instance of {@link ToOptional}.
* <p>
* Note: This always returns the same {@link Collector}.
*/
@SuppressWarnings("unchecked")
public static <T> ToOptional<T> get() {
return (ToOptional<T>) INSTANCE;
}
static class Ref<RT> {
private RT value;
private int count = 0;
public void set(RT value) {
this.value = value;
this.count++;
}
public RT get() {
return this.value;
}
public int getCount() {
return this.count;
}
}
@Override
public Supplier<Ref<T>> supplier() {
return Ref<T>::new;
}
@Override
public BiConsumer<Ref<T>, T> accumulator() {
return (ref, value) -> {
ref.set(value);
};
}
@Override
public BinaryOperator<Ref<T>> combiner() {
return (ref1, ref2) -> {
if (ref1.getCount() == 0)
return ref2;
if (ref2.getCount() == 0)
return ref1;
ref1.set(null);// increments count
return ref1;
};
}
@Override
public Function<Ref<T>, Optional<T>> finisher() {
return (ref) -> {
if (ref.getCount() != 1)
return Optional.empty();
return Optional.ofNullable(ref.get());
};
}
@Override
public Set<java.util.stream.Collector.Characteristics> characteristics() {
return Collections.emptySet();
}
}
Comments
0 B
|👍
/👎