Calling different methods based on values of two Optionals - java

While working with Java 8 Optionals I face following scenario very frequently. I have two Optional objects and then I want to call different methods based on the values (ifPresent) of those Optionals.
Here is an example:
void example(Optional<String> o1, Optional<String> o2) throws Exception {
if (o1.isPresent() && o2.isPresent()) {
handler1(o1.get(), o2.get());
} else if (o1.isPresent()) {
handler2(o1.get());
} else if (o2.isPresent()) {
handler3(o2.get());
} else {
throw new Exception();
}
}
However, this chain of if-else statements doesn't seem like a proper way of working with Optional (after all, they were added so that you can avoid writing these if-else checks everywhere in your code).
What is the proper way of doing this with Optional objects?

You said that you use such structure frequently, so I propose to introduce a Helper class:
final class BiOptionalHelper<F, S> {
private final Optional<F> first;
private final Optional<S> second;
public BiOptionalHelper(Optional<F> first, Optional<S> second){
this.first = first;
this.second = second;
}
public BiOptionalHelper<F, S> ifFirstPresent(Consumer<? super F> ifPresent){
if (!second.isPresent()) {
first.ifPresent(ifPresent);
}
return this;
}
public BiOptionalHelper<F, S> ifSecondPresent(Consumer<? super S> ifPresent){
if (!first.isPresent()) {
second.ifPresent(ifPresent);
}
return this;
}
public BiOptionalHelper<F, S> ifBothPresent(BiConsumer<? super F, ? super S> ifPresent){
if(first.isPresent() && second.isPresent()){
ifPresent.accept(first.get(), second.get());
}
return this;
}
public <T extends Throwable> void orElseThrow(Supplier<? extends T> exProvider) throws T{
if(!first.isPresent() && !second.isPresent()){
throw exProvider.get();
}
}
}
Which then may be used in a way like this:
new BiOptionalHelper<>(o1, o2)
.ifBothPresent(this::handler1)
.ifFirstPresent(this::handler2)
.ifSecondPresent(this::handler3)
.orElseThrow(Exception::new);
Though, this just moves your problem into a separate class.
Note: above code may be refactored to not use Optional and isPresent() checks at all. And just use null for first and second and replace isPresent() with null-checks.
As it is generally a bad design to store Optional in fields or accept them as parameters in the first place. As JB Nizet already pointed out in a comment to the question.
Another way it to move that logic into common helper method:
public static <F, S, T extends Throwable> void handle(Optional<F> first, Optional<S> second,
BiConsumer<F, S> bothPresent, Consumer<F> firstPresent,
Consumer<S> secondPresent, Supplier<T> provider) throws T{
if(first.isPresent() && second.isPresent()){
bothPresent.accept(first.get(), second.get());
} else if(first.isPresent()){
firstPresent.accept(first.get());
} else if(second.isPresent()){
secondPresent.accept(second.get());
} else{
throw provider.get();
}
}
Which then could be called like this:
handle(o1, o2, this::handler1, this::handler2, this::handler3, Exception::new);
But it's still kind of messy to be honest.

Disclaimer: My answer is based on Lino's answer - the first part of this answer (BiOptional<T, U>) is a modified version of Lino's BiOptionalHelper, while the second part (BiOptionalMapper<T, U, R>) is my idea for extending this nice pattern.
I like Lino's answer a lot. However, I feel that instead of calling it BiOptionalHelper, it deserves to be simply called BiOptional, provided that:
it gets Optional<T> first() and Optional<T> second() methods
it gets is(First/Second)Present, is(First/Second)OnlyPresent and are(Both/None)Present methods
if(First/Second)Present methods are renamed to if(First/Second)OnlyPresent
it gets ifNonePresent(Runnable action) method
orElseThrow method is renamed to ifNonePresentThrow
Finally (and this is the entirely original part of my answer), I realized this pattern could support not only "handling" (in BiOptional), but also "mapping" (in BiOptionalMapper obtained through BiOptional.mapper()), like that:
BiOptional<String, Integer> biOptional = BiOptional.from(o1, o2);
// handler version
biOptional
.ifBothPresent(this::handleBoth)
.ifFirstOnlyPresent(this::handleFirst)
.ifSecondOnlyPresent(this::handleSecond)
.ifNonePresent(this::performAction);
// mapper version
String result = biOptional.<String>mapper()
.onBothPresent(this::mapBoth)
.onFirstOnlyPresent(this::mapFirst)
.onSecondOnlyPresent(this::mapSecond)
.onNonePresent("default")
.result();
Optional<String> optionalResult = biOptional.<String>mapper()
.onBothPresent(this::mapBoth)
.onNonePresentThrow(IllegalStateException::new)
.optionalResult();
Note that one can either:
call all on*Present mapping methods, and then call R result() (which will throw if result were to be absent), or
call only some of them, and then call Optional<R> optionalResult()
Note also that:
in order to avoid confusion between "handling" and "mapping", the naming convention is as follows:
BiOptional: if*Present
BiOptionalMapper: on*Present
if any of the on*Present methods is called twice, BiOptionalMapper will throw if result were to be overwritten (unlike BiOptional, which can handle multiple if*Present calls)
result cannot be set to null by the mappers provided to on*Present or by calling onNonePresent(R) (Optional<...> should be used as result type R instead)
Here's the source code of the two classes:
final class BiOptional<T, U> {
#Nullable
private final T first;
#Nullable
private final U second;
public BiOptional(T first, U second) {
this.first = first;
this.second = second;
}
public static <T, U> BiOptional<T, U> from(Optional<T> first, Optional<U> second) {
return new BiOptional<>(first.orElse(null), second.orElse(null));
}
public Optional<T> first() {
return Optional.ofNullable(first);
}
public Optional<U> second() {
return Optional.ofNullable(second);
}
public boolean isFirstPresent() {
return first != null;
}
public boolean isSecondPresent() {
return second != null;
}
public boolean isFirstOnlyPresent() {
return isFirstPresent() && !isSecondPresent();
}
public boolean isSecondOnlyPresent() {
return !isFirstPresent() && isSecondPresent();
}
public boolean areBothPresent() {
return isFirstPresent() && isSecondPresent();
}
public boolean areNonePresent() {
return !isFirstPresent() && !isSecondPresent();
}
public BiOptional<T, U> ifFirstOnlyPresent(Consumer<? super T> ifFirstOnlyPresent) {
if (isFirstOnlyPresent()) {
ifFirstOnlyPresent.accept(first);
}
return this;
}
public BiOptional<T, U> ifSecondOnlyPresent(Consumer<? super U> ifSecondOnlyPresent) {
if (isSecondOnlyPresent()) {
ifSecondOnlyPresent.accept(second);
}
return this;
}
public BiOptional<T, U> ifBothPresent(BiConsumer<? super T, ? super U> ifBothPresent) {
if (areBothPresent()) {
ifBothPresent.accept(first, second);
}
return this;
}
public BiOptional<T, U> ifNonePresent(Runnable ifNonePresent) {
if (areNonePresent()) {
ifNonePresent.run();
}
return this;
}
public <X extends Throwable> void ifNonePresentThrow(Supplier<? extends X> throwableProvider) throws X {
if (areNonePresent()) {
throw throwableProvider.get();
}
}
public <R> BiOptionalMapper<T, U, R> mapper() {
return new BiOptionalMapper<>(this);
}
}
and:
final class BiOptionalMapper<T, U, R> {
private final BiOptional<T, U> biOptional;
private R result = null;
BiOptionalMapper(BiOptional<T, U> biOptional) {
this.biOptional = biOptional;
}
public BiOptionalMapper<T, U, R> onFirstOnlyPresent(Function<? super T, ? extends R> firstMapper) {
if (biOptional.isFirstOnlyPresent()) {
setResult(firstMapper.apply(biOptional.first().get()));
}
return this;
}
public BiOptionalMapper<T, U, R> onSecondOnlyPresent(Function<? super U, ? extends R> secondMapper) {
if (biOptional.isSecondOnlyPresent()) {
setResult(secondMapper.apply(biOptional.second().get()));
}
return this;
}
public BiOptionalMapper<T, U, R> onBothPresent(BiFunction<? super T, ? super U, ? extends R> bothMapper) {
if (biOptional.areBothPresent()) {
setResult(bothMapper.apply(biOptional.first().get(), biOptional.second().get()));
}
return this;
}
public BiOptionalMapper<T, U, R> onNonePresent(Supplier<? extends R> supplier) {
if (biOptional.areNonePresent()) {
setResult(supplier.get());
}
return this;
}
public BiOptionalMapper<T, U, R> onNonePresent(R other) {
if (biOptional.areNonePresent()) {
setResult(other);
}
return this;
}
public <X extends Throwable> BiOptionalMapper<T, U, R> onNonePresentThrow(Supplier<? extends X> throwableProvider) throws X {
biOptional.ifNonePresentThrow(throwableProvider);
return this;
}
public R result() {
if (result == null) {
throw new IllegalStateException("Result absent");
}
return result;
}
public Optional<R> optionalResult() {
return Optional.ofNullable(result);
}
private void setResult(R result) {
if (result == null) {
throw new IllegalArgumentException("Null obtained from a mapper");
}
if (this.result != null) {
throw new IllegalStateException("Result already present: " + this.result);
}
this.result = result;
}
}

It doesn’t really answer your question, but since Java 9 I would prefer something along these lines:
o1.ifPresentOrElse(s1 -> {
o2.ifPresentOrElse(s2 -> {
handler1(s1, s2);
}, () -> {
handler2(s1);
});
}, () -> {
o2.ifPresentOrElse(s2 -> {
handler3(s2);
}, () -> {
throw new IllegalArgumentException("Neither was present");
});
});
There’s a rule of thumb about Optional saying not to use isPresent and get. I do use them very occasionally; most often they are better avoided.

To avoid if statements or here if (Optional.isPresent()) you should have a common way to handle the Optional values but it is not the case as according their content you may invoke a function with the functional interface Consumer<String> or BiConsumer<String, String>.
As hint, you may factor the second part but it is not more readable or a better way :
if (o1.isPresent() && o2.isPresent()) {
handler1(o1.get(), o2.get());
} else {
Map<Optional<String>, Consumer<String>> map = new HashMap<>();
map.put(o1, this::handler2);
map.put(o2, this::handler3);
Optional<String> opt = Stream.of(o1, o2)
.filter(Optional::isPresent)
.findFirst()
.orElseThrow(Exception::new);
map.get(opt)
.accept(opt.get());
}
If you have much more Optionals to handle in this way such as this would probably make more sense but still it is a lot of code to write.
A more readable alternative could be to introduce a Rule class that stores the information required to trigger that if required :
public Rule(BiPredicate<Optional<String>, Optional<String>> ruleFunction, Runnable runnableIfApplied) {
this.ruleFunction = ruleFunction;
this.runnable = runnableIfApplied;
}
The BiPredicate<Optional<String>, Optional<String>> represents the matching function and the Runnable is the method to execute if the matching occurs.
You could move the rule execution logic in a Rule static method.
The idea is to make as clear as possible the rule specifications from the client side such as :
void example(Optional<String> o1, Optional<String> o2, Optional<String> o3) throws Exception {
Rule.executeFirstMatchOrFail(o1, o2,
new Rule((opt1, opt2) -> opt1.isPresent() && opt2.isPresent(), () -> handler1(o1.get(), o2.get())),
new Rule((opt1, opt2) -> opt1.isPresent(), () -> handler2(o1.get())),
new Rule((opt1, opt2) -> opt2.isPresent(), () -> handler3(o2.get())));
}
Rule could look like :
public class Rule {
static void executeFirstMatchOrFail(Optional<String> o1, Optional<String> o2, Rule... rules) throws Exception {
for (Rule rule : rules) {
if (rule.apply(o1, o2)) {
return;
}
}
throw new Exception();
}
private Runnable runnable;
private BiPredicate<Optional<String>, Optional<String>> ruleFunction;
public Rule(BiPredicate<Optional<String>, Optional<String>> ruleFunction, Runnable runnableIfApplied) {
this.ruleFunction = ruleFunction;
this.runnable = runnableIfApplied;
}
public boolean apply(Optional<String> o1, Optional<String> o2) {
if (ruleFunction.test(o1,o2)) {
runnable.run();
return true;
}
return false;
}
}

Related

Casting Predicate<> to a child type

I have a custom implementation of a Predicate that I want to use in some operations.
However, I am having a hard type making polymorphism work with it.
After some investigation I wrote the minimal code below to reproduce the problem (which is a better explanation of the problem than I could describe).
class Custom implements Predicate<Integer> {
int y;
public Custom(int y) {
this.y = y;
}
#Override
public boolean test(Integer i) {
return y+i>0;
}
}
public class Main{
public static void main(String[] args) {
Custom c1 = new Custom(5);
Custom c2 = new Custom(8);
Custom c = (Custom) c1.and(c2); // faulty line - unable to cast
}
}
I am unsure why the casting fails and how to make it work.
If you want to preserve state of your Custom objects and implement the Predicate interface I would suggest to overload the and, or and negate methods. When you combine two Custom objects with and, or or when you call negate you will get a Custom object as return value. When you combine a Custom object with any other implementation of Predicate<Integer the methods will still return Predicate<Integer:
class Custom implements Predicate<Integer> {
class And extends Custom {
Custom a;
Custom b;
public And(Custom a, Custom b) {
super((i) -> a.test(i) && b.test(i));
this.a = a;
this.b = b;
}
}
class Or extends Custom {
Custom a;
Custom b;
public Or(Custom a, Custom b) {
super((i) -> a.test(i) || b.test(i));
this.a = a;
this.b = b;
}
}
class Not extends Custom {
Custom custom;
public Not(Custom custom) {
super((i) -> !custom.test(i));
this.custom = custom;
}
}
private final Predicate<Integer> predicate;
public Custom(int y) {
this((i) -> y + i > 0);
}
private Custom(Predicate<Integer> predicate) {
this.predicate = predicate;
}
#Override
public boolean test(Integer i) {
return predicate.test(i);
}
public Custom.And and(Custom other) {
return new Custom.And(this, other);
}
public Custom.Or or(Custom other) {
return new Custom.Or(this, other);
}
public Custom.Not negate() {
return new Custom.Not(this);
}
}
I don't see a good reason of creating such a type of predicate as it complicates your predicates. However, there are at least 3 different ways that come to my mind "changing" the predicate state.
v0 - simply use java.util.function.Predicate<T>
final Predicate<String> p1 = "foo"::equals;
final Predicate<String> unit1 = p1.or("bar"::equals);
Assertions.assertTrue(unit1.test("foo"));
Assertions.assertTrue(unit1.test("bar"));
Assertions.assertFalse(unit1.test("baz"));
final Predicate<String> unit2 = p1.or("baz"::equals);
Assertions.assertTrue(unit2.test("foo"));
Assertions.assertTrue(unit2.test("baz"));
There is nothing wrong with this code and I would still go with it not implementing any custom classes.
v1 - "do cast" in a custom predicate implementation
This still requires all default methods from the Predicate<T> interface to be overridden in order not to break in a future Java release.
public abstract class V1MutablePredicate<T, P extends V1MutablePredicate<T, P>>
implements Predicate<T> {
#Nullable
private final Predicate<T> predicate;
protected V1MutablePredicate(#Nullable final Predicate<T> predicate) {
this.predicate = predicate;
}
protected abstract boolean doTest(T t);
#Nonnull
protected abstract P wrap(#Nonnull Predicate<T> predicate);
#Override
public final boolean test(final T t) {
return predicate == null ? doTest(t) : predicate.test(t);
}
#Nonnull
#Override
public final P and(#Nonnull final Predicate<? super T> other) {
return wrap(Predicate.super.and(other));
}
#Nonnull
#Override
public final P negate() {
return wrap(Predicate.super.negate());
}
#Nonnull
#Override
public final P or(#Nonnull final Predicate<? super T> other) {
return wrap(Predicate.super.or(other));
}
}
private static final class Custom
extends V1MutablePredicate<String, Custom> {
private String s;
Custom(final String s) {
this(null, s);
}
private Custom(#Nullable final Predicate<String> predicate, final String s) {
super(predicate);
this.s = s;
}
#Override
protected boolean doTest(final String t) {
return t.equals(s);
}
#Nonnull
#Override
protected Custom wrap(#Nonnull final Predicate<String> predicate) {
return new Custom(predicate, s);
}
}
#Test
public void test() {
final Custom p1 = new Custom("foo");
final Custom p2 = new Custom("bar");
final Custom unit = p1.or(p2);
Assertions.assertTrue(unit.test("foo"));
Assertions.assertTrue(unit.test("bar"));
Assertions.assertFalse(unit.test("baz"));
p2.s = "baz";
Assertions.assertTrue(unit.test("foo"));
Assertions.assertTrue(unit.test("baz"));
}
This one seems to be closest to what you want to accomplish.
v2 - inject the predicate state from outside
public final class V2MutablePredicate<T, S>
implements Predicate<T> {
private final Supplier<? extends S> stateSupplier;
private final BiPredicate<? super S, ? super T> predicate;
public V2MutablePredicate(final Supplier<? extends S> stateSupplier, final BiPredicate<? super S, ? super T> predicate) {
this.stateSupplier = stateSupplier;
this.predicate = predicate;
}
#Override
public boolean test(final T t) {
return predicate.test(stateSupplier.get(), t);
}
}
final AtomicReference<String> r1 = new AtomicReference<>("foo");
final V2MutablePredicate<String, String> p1 = new V2MutablePredicate<>(r1::get, String::equals);
final AtomicReference<String> r2 = new AtomicReference<>("bar");
final V2MutablePredicate<String, String> p2 = new V2MutablePredicate<>(r2::get, String::equals);
final Predicate<String> unit = p1.or(p2);
Assertions.assertTrue(unit.test("foo"));
Assertions.assertTrue(unit.test("bar"));
Assertions.assertFalse(unit.test("baz"));
r2.set("baz");
Assertions.assertTrue(unit.test("foo"));
Assertions.assertTrue(unit.test("baz"));
This implementation requires the state to be changed from outside managing multiple objects to be handled and it also requires "state" classes, but it does not require the default methods to be overridden and also requires the supplier to provide the value in every test method call.

Implementing map function

I am creating a 'SpecialList' and am require to implement the map function. The list should be lazy, and will only produce values when evaluated.
toString() returns "?" if the value is not yet available; returns the string representation of the value otherwise.
get() called when the contents is needed. If the value is already available, return that value; otherwise, compute the value and return it. The computation should only be done once for the same value.
Here's what I have:
public <U> SpecialList<U> map(Function<T, U> mapper) {
if (!this.isAvailable) {
return new SpecialList<U>(this.supplier);
}
return new SpecialList<U>(mapper, value);
}
// private constructor
private SpecialList(CachedSupplier<T> s) {
this.supplier = s;
this.isAvailable = false;
}
However, it is telling me that there's no valid constuctor because T cannot be converted to U.
SpecialList.java:65: error: no suitable constructor found for SpecialList(SpecialList<T>.CachedSupplier<T>)
return new SpecialList<U>(this.supplier);
^
constructor SpecialList.SpecialList(U) is not applicable
(argument mismatch; SpecialList<T>.CachedSupplier<T> cannot be converted to U)
constructor SpecialList.SpecialList(Supplier<U>) is not applicable
(argument mismatch; SpecialList<T>.CachedSupplier<T> cannot be converted to Supplier<U>)
Doesn't the 'U' become a T when returned?
How do I go about solving this? I am still a little unclear about the method level generic types. But I was told that I need to add the < U > for my map method.
Below is my code in full:
class SpecialList<T> {
class CachedSupplier<T> {
private Supplier<? extends T> supplier;
private T value;
boolean isAvailable;
public CachedSupplier(Supplier<? extends T> supplier) {
this.supplier = supplier;
}
public T get() {
if (!isAvailable) {
value = supplier.get();
isAvailable = true;
}
return value;
}
}
private CachedSupplier<T> supplier;
private T value;
boolean isAvailable;
private SpecialList(T value) {
this.value = value;
this.isAvailable = true;
}
private SpecialList(Supplier<T> s) {
this.supplier = new CachedSupplier<T>(s);
this.isAvailable = false;
}
private SpecialList(CachedSupplier<T> s) {
this.supplier = s;
this.isAvailable = false;
}
private <R> SpecialList(Function<T, R> mapper, T v) {
this.supplier = new CachedSupplier<T>(() -> mapper.apply(v));
this.isAvailable = false;
}
public static <T> SpecialList<T> of(T value) {
return new SpecialList<>(value);
}
public static <T> SpecialList<T> of(Supplier<T> supplier) {
return new SpecialList<>(supplier);
}
public <R> SpecialList<R> map(Function<? super T,? extends R> mapper) {
if (!this.isAvailable) {
return new SpecialList<>(this.supplier);
}
return new SpecialList<R>(mapper, value);
}
public T get() {
if(this.isAvailable) {
return this.value;
} else {
this.value = this.supplier.get();
this.isAvailable = true;
return this.value;
}
}
}
I am still a little confused with Generic Types etc. so please let me know if there's anything odd/I can improve!
Thanks
According to the code you posted, there is a compile-time error in one of the constructors for class SpecialList...
private <R> SpecialList(Function<T, R> mapper, T v) {
this.supplier = new CachedSupplier<T>(() -> mapper.apply(v));
this.isAvailable = false;
}
Firstly, in the code you posted, there is no constructor in inner class CachedSupplier that takes a Function parameter, so you need to add one with this signature:
public <R> CachedSupplier(Function<T, R> mapper)
And the second problem with the SpecialList constructor is the lambda expression. Abstract method apply in interface Function has a parameter, which your lambda expression is missing. So the constructor code should be:
private <R> SpecialList(Function<T, R> mapper, T v) {
this.supplier = new CachedSupplier<T>((v) -> mapper.apply(v));
this.isAvailable = false;
}
The problem is your map function is changing the SpecialList type parameter from T to R. But in the fragment highlited by compiler you return still SpecialList.
Things you can do:
If you are not planning to change the type of elements with your map() function, get rid of R, and replace Function<? super T,? extends R> mapper with Function<? super T,? extends T> mapper. However, this way the mapper would be totaly omited, which might not be the desired behaviuor.
Otherwise, you should pass into your SpecialList constructor a combination of the original supplier and new mapper like so:
return new SpecialList<R>(() -> {
T originalValue = this.supplier.get();
return mapper.apply(originalValue);
};
I think you're doing an overkill by checking isAvailable in both, the SpecialList and the CachedSupplier. It seems enough to me to do so in the CachedSupplier and reduce the members of SpecialList to just the supplier (which is, when the value is available, simply a value-getter without additional costly evaluations). And in the constructors you make sure that the supplier is a cached one, when needed (i.e. when you don't have the value yet).
So here's my suggestion. Further comments are directly in the source code (which compiles now without errors or warnings):
class SpecialList<T> {
static class CachedSupplier<R> implements Supplier<R> {
/* R is a priori an idependent parameter. If you call it T again, then you get a warning
* that the original T is hidden within the new nested class (though it wouldn't really matter here),
* as one doesn't need to refer to it. I made it static, as you don't need an instance to define it. */
private Supplier<? extends R> supplier;
private R value;
boolean isAvailable;
public CachedSupplier(Supplier<? extends R> supplier) {
this.supplier = supplier;
this.isAvailable = false;
}
#Override
public R get() {
if (!isAvailable) {
value = supplier.get();
isAvailable = true;
}
return value;
}
}
private Supplier<T> supplier;
private SpecialList(T value) {
/* in this case no lazy evaluation and no caching needed */
this.supplier = () -> value;
}
private SpecialList(Supplier<T> s) {
this.supplier = new CachedSupplier<T>(s);
}
private SpecialList(CachedSupplier<T> s) {
this.supplier = s;
}
private <R> SpecialList(Function<R, T> mapper, R v) {
/* This constructor is not needed anymore in my suggested code.
* I left it simply, in order to show how to fix the type errors related to it.
* if I understood correctly the intentions of this constructor,
* R and T have to be swapped w.r.t the original post.
* This is a constructor that uses an R-value and a mapper R->T to create a SpecialList<T> */
this.supplier = new CachedSupplier<T>(() -> mapper.apply(v));
}
public static <T> SpecialList<T> of(T value) {
return new SpecialList<>(value);
}
public static <T> SpecialList<T> of(Supplier<T> supplier) {
return new SpecialList<>(supplier);
}
public <R> SpecialList<R> map(Function<T, R> mapper) {
/* mapper is here different (opposite direction) than in the last of the constructors.
* Here we have an existing SpecialList containing a value of Type T which will be turned into a
* SpecialList containing a value of type R by applying a mapper T->R after getting the value from
* the original SpecialList */
return new SpecialList<R>(() -> mapper.apply(get()));
}
public T get() {
return this.supplier.get();
}
}
This solution doesn't yet take care of the toString() implementation. When you want to implement also the latter, it might be more natural to make SpecialList a subclass of CachedSupplier (with the additional map- and toString- methods and direct access to isAvailable)

How to implement a parallel supporting takeWhile for the Stream API in Java 8?

I've seen some takeWhile implementations for the Java 8 stream API but they all seem to turn the stream into a non-parallel stream. For example this one:
static <T> Spliterator<T> takeWhile(
Spliterator<T> splitr, Predicate<? super T> predicate) {
return new Spliterators.AbstractSpliterator<T>(splitr.estimateSize(), 0) {
boolean stillGoing = true;
#Override public boolean tryAdvance(Consumer<? super T> consumer) {
if (stillGoing) {
boolean hadNext = splitr.tryAdvance(elem -> {
if (predicate.test(elem)) {
consumer.accept(elem);
} else {
stillGoing = false;
}
});
return hadNext && stillGoing;
}
return false;
}
};
}
static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<? super T> predicate) {
return StreamSupport.stream(takeWhile(stream.spliterator(), predicate), false);
}
Here StreamSupport.stream(takeWhile(stream.spliterator(), predicate), false); turns the stream passed to takeWhile into a sequential stream. Is anyone aware of an implementation that supports parallel streams or how can I modify this code to make it maintain/support parallel streams?
If your source is known to be unordered, then the following implementation should work:
static final class UnorderedTakeWhileSpliterator<T> implements Spliterator<T>, Consumer<T>, Cloneable {
private final Predicate<? super T> predicate;
private final AtomicBoolean checked = new AtomicBoolean();
private Spliterator<T> source;
private T cur;
UnorderedTakeWhileSpliterator(Spliterator<T> source, Predicate<? super T> predicate) {
this.predicate = predicate;
this.source = source;
}
#Override
public void accept(T t) {
this.cur = t;
}
#Override
public boolean tryAdvance(Consumer<? super T> action) {
if (!checked.get() && source.tryAdvance(this)) {
if (predicate.test(cur)) {
action.accept(cur);
return true;
} else {
checked.set(true);
}
}
return false;
}
#Override
public Spliterator<T> trySplit() {
Spliterator<T> prefix = source.trySplit();
if(prefix == null) {
return null;
}
if(checked.get()) {
return Spliterators.emptySpliterator();
}
UnorderedTakeWhileSpliterator<T> clone;
try {
clone = (UnorderedTakeWhileSpliterator<T>) clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
clone.source = prefix;
return clone;
}
#Override
public long estimateSize() {
return source.estimateSize();
}
#Override
public int characteristics() {
return source.characteristics() & (DISTINCT | SORTED | NONNULL);
}
#Override
public Comparator<? super T> getComparator() {
return source.getComparator();
}
}
Create the stream with the following method:
static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<? super T> predicate) {
return StreamSupport.stream(UnorderedTakeWhileSpliterator<>(stream.spliterator(), predicate), stream.isParallel());
}
Ordered implementation would be much more tricky as it should buffer non-prefixed items and propagate the cancelling to the suffixes. Something like this is implemented in JDK-9 (not as spliterator, but as normal stream operation), but I doubt that even this tricky implementation wins in many cases over sequential stream.

Abstract Class with enum Comparator: How to make it work?

I would like to get the following thing to work. My abstract class T extends java.util.Comparator<T> and should therefore allow me to use the compareTo method. The problem is that o1.t1.compareTo(o2.t1) receives The method compareTo(capture#2-of ?) is undefined for the type capture#1-of ?
Could someone please explain the problem on a basic level and tell me how to potentially fix it? Thanks a lot in advance.
public class TypeTypeComparator<T extends java.util.Comparator<T>> {
public T t1;
public T t2;
public TypeTypeComparator() {
this.t1 = null;
this.t2 = null;
}
public TypeTypeComparator(T t1, T t2) {
this.t1 = t1;
this.t2 = t2;
}
public static enum Comparator implements java.util.Comparator<TypeTypeComparator<?>> {
T1_SORT {
public int compare(TypeTypeComparator<?> o1, TypeTypeComparator<?> o2) {
return o1.t1.compareTo(o2.t1);
}},
T2_SORT {
public int compare(TypeTypeComparator<?> o1, TypeTypeComparator<?> o2) {
return o1.t2.compareTo(o2.t2);
}};
public static java.util.Comparator<TypeTypeComparator<?>> getComparator(final Comparator... options) {
return new java.util.Comparator<TypeTypeComparator<?>>() {
public int compare(TypeTypeComparator<?> o1, TypeTypeComparator<?> o2) {
for ( Comparator option : options ) {
int result = option.compare(o1, o2);
if ( result != 0 )
return result;
}
return 0;
}
};
}
}
}
There were few issues in your implementation, I have solved the issues for you :)
1st issue
public class TypeTypeComparator<T extendsjava.util.Comparator<T>> {
You need Comparable here instead of a Comparator here. So it becomes
public class TypeTypeComparator<T extendsComparable<T>> {
2nd issue
Recursive generics in Comparable forces you to use ? for generics
public static enum Comparator implementsjava.util.Comparator<TypeTypeComparator<?>>
or
public static enum Comparator implements java.util.Comparator<TypeTypeComparator<Comparable<?>>>
You will again need to put ? due to recursive generic declaration in Comparable, so instead I recommend you resolve the recursive generics of Comparable as follows:
interface Comp extends java.lang.Comparable<Comp> {}
Now you need to replace all ? with Comp and you are done.
Here is the complete implementation:
interface Comp extends Comparable<Comp> {}
public class TypeTypeComparator<T extends Comp> {
public T t1;
public T t2;
public TypeTypeComparator() {
this.t1 = null;
this.t2 = null;
}
public TypeTypeComparator(T t1, T t2) {
this.t1 = t1;
this.t2 = t2;
}
public static enum Comparator implements java.util.Comparator<TypeTypeComparator<Comp>> {
T1_SORT {
#Override
public int compare(TypeTypeComparator<Comp> o1,
TypeTypeComparator<Comp> o2) {
return o1.t1.compareTo(o2.t1);
}
},
T2_SORT {
#Override
public int compare(TypeTypeComparator<Comp> o1,
TypeTypeComparator<Comp> o2) {
return o1.t2.compareTo(o2.t2);
}
};
public static java.util.Comparator<TypeTypeComparator<Comp>> getComparator(final Comparator... options) {
return new java.util.Comparator<TypeTypeComparator<Comp>>() {
public int compare(TypeTypeComparator<Comp> o1, TypeTypeComparator<Comp> o2) {
for ( Comparator option : options ) {
int result = option.compare(o1, o2);
if ( result != 0 )
return result;
}
return 0;
}
};
}
}
}
I would replace Comparator<TypeTypeComparator<?>> with Comparator<TypeTypeComparator> The problem is that one <?> and another are not equivalent.
BTW It appear you really want to be using Java 8 which would make all of this trivial. Java 7 will be End Of Life'd in April.
In Java 8 you would need a class like you have i.e. all the code would disappear. You can use built in functions like
list.sort(comparing(Type::getField1)
.andThen(comparing(t -> getItem().getOtherField())
.andThen(comparing(Type::getField2).reversed()));

Getting the next item from a Java 8 stream

I'd like to retrieve and remove the next item from a Java 8 Stream, without this Stream getting closed.
Stream<Integer> integerStream = Stream.iterate( 0, x -> new Integer(x + 1) );
Integer zero = integerStream.getNext(); // 0
Integer one = integerStream.getNext(); // 1
...
Is this possible?
Yes, there is a way to do this, but with some limitations.
Stream<Integer> infiniteStream = Stream.iterate( 0, x -> new Integer(x + 1) );
Iterator<Integer> iter = infiniteStream.iterator();
Integer zero = iter.next();
Integer one = iter.next();
Alternatively,
Stream<Integer> infiniteStream = Stream.iterate( 0, x -> new Integer(x + 1) );
Spliterator<Integer> spliterator = infiniteStream.spliterator();
spliterator.tryAdvance(i -> System.out.println(i)); // zero
spliterator.tryAdvance(i -> System.out.println(i)); // one
Given a Stream, it's possible to get an Iterator or Spliterator from it, or to query whether it's a parallel stream, etc. These are defined on the BaseStream interface, a superinterface of Stream, which makes them a bit easy to miss.
In this case we know the stream is infinite, so there is no need to call the Iterator's hasNext() method or to check the return value of the Spliterator's tryAdvance()
The limitation is that both the iterator() and spliterator() methods of Stream are terminal operations which means that after they're called, the returned Iterator or Spliterator has exclusive access to the values represented by the Stream. Further operations on the stream (such as filter or map and so forth) are not permitted and will be met with IllegalStateException.
If you wanted to peel off the first couple elements and then resume stream processing, you could turn a spliterator back into a stream like so:
Stream<Integer> stream2 = StreamSupport.stream(spliterator, false);
This will probably work fine for some things, but I'm not sure I'd recommend this technique in general. I think it adds a few extra objects and thus extra method calls in the path of producing the next element.
Editorial comments (not related to your question):
Don't use new Integer(val). Instead use Integer.valueOf(val) which will reuse the boxed integer if it's available, which is generally true for values in the range -128 to 127.
You can use IntStream instead of Stream<Integer> which avoids boxing overhead entirely. It doesn't have the full complement of stream operations, but it does have iterate() which takes a function that operates on primitive int values.
Based on Stuart's answer and with an Iterator-to-Stream conversion, I came up with the following quick-and-dirty wrapper class. It's not tested, and it's not thread-safe, but it provides me with what I currently need — removing and using single items while keeping this stream "open".
PeelingStream<T> provides a method T getNext() that shields away someWrappedStream.iterator()'s terminal stream operation semantics:
public class PeelingStream<T> implements Stream<T> {
private Stream<T> wrapped;
public PeelingStream(Stream<T> toBeWrapped) {
this.wrapped = toBeWrapped;
}
public T getNext() {
Iterator<T> iterator = wrapped.iterator();
T next = iterator.next();
Iterable<T> remainingIterable = () -> iterator;
wrapped = StreamSupport.stream(remainingIterable.spliterator(),
false);
return next;
}
///////////////////// from here, only plain delegate methods
public Iterator<T> iterator() {
return wrapped.iterator();
}
public Spliterator<T> spliterator() {
return wrapped.spliterator();
}
public boolean isParallel() {
return wrapped.isParallel();
}
public Stream<T> sequential() {
return wrapped.sequential();
}
public Stream<T> parallel() {
return wrapped.parallel();
}
public Stream<T> unordered() {
return wrapped.unordered();
}
public Stream<T> onClose(Runnable closeHandler) {
return wrapped.onClose(closeHandler);
}
public void close() {
wrapped.close();
}
public Stream<T> filter(Predicate<? super T> predicate) {
return wrapped.filter(predicate);
}
public <R> Stream<R> map(Function<? super T, ? extends R> mapper) {
return wrapped.map(mapper);
}
public IntStream mapToInt(ToIntFunction<? super T> mapper) {
return wrapped.mapToInt(mapper);
}
public LongStream mapToLong(ToLongFunction<? super T> mapper) {
return wrapped.mapToLong(mapper);
}
public DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper) {
return wrapped.mapToDouble(mapper);
}
public <R> Stream<R> flatMap(
Function<? super T, ? extends Stream<? extends R>> mapper) {
return wrapped.flatMap(mapper);
}
public IntStream flatMapToInt(
Function<? super T, ? extends IntStream> mapper) {
return wrapped.flatMapToInt(mapper);
}
public LongStream flatMapToLong(
Function<? super T, ? extends LongStream> mapper) {
return wrapped.flatMapToLong(mapper);
}
public DoubleStream flatMapToDouble(
Function<? super T, ? extends DoubleStream> mapper) {
return wrapped.flatMapToDouble(mapper);
}
public Stream<T> distinct() {
return wrapped.distinct();
}
public Stream<T> sorted() {
return wrapped.sorted();
}
public Stream<T> sorted(Comparator<? super T> comparator) {
return wrapped.sorted(comparator);
}
public Stream<T> peek(Consumer<? super T> action) {
return wrapped.peek(action);
}
public Stream<T> limit(long maxSize) {
return wrapped.limit(maxSize);
}
public Stream<T> skip(long n) {
return wrapped.skip(n);
}
public void forEach(Consumer<? super T> action) {
wrapped.forEach(action);
}
public void forEachOrdered(Consumer<? super T> action) {
wrapped.forEachOrdered(action);
}
public Object[] toArray() {
return wrapped.toArray();
}
public <A> A[] toArray(IntFunction<A[]> generator) {
return wrapped.toArray(generator);
}
public T reduce(T identity, BinaryOperator<T> accumulator) {
return wrapped.reduce(identity, accumulator);
}
public Optional<T> reduce(BinaryOperator<T> accumulator) {
return wrapped.reduce(accumulator);
}
public <U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner) {
return wrapped.reduce(identity, accumulator, combiner);
}
public <R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner) {
return wrapped.collect(supplier, accumulator, combiner);
}
public <R, A> R collect(Collector<? super T, A, R> collector) {
return wrapped.collect(collector);
}
public Optional<T> min(Comparator<? super T> comparator) {
return wrapped.min(comparator);
}
public Optional<T> max(Comparator<? super T> comparator) {
return wrapped.max(comparator);
}
public long count() {
return wrapped.count();
}
public boolean anyMatch(Predicate<? super T> predicate) {
return wrapped.anyMatch(predicate);
}
public boolean allMatch(Predicate<? super T> predicate) {
return wrapped.allMatch(predicate);
}
public boolean noneMatch(Predicate<? super T> predicate) {
return wrapped.noneMatch(predicate);
}
public Optional<T> findFirst() {
return wrapped.findFirst();
}
public Optional<T> findAny() {
return wrapped.findAny();
}
}
A small test:
#Test
public void testPeelingOffItemsFromStream() {
Stream<Integer> infiniteStream = Stream.iterate(0, x -> x + 1);
PeelingStream<Integer> peelingInfiniteStream = new PeelingStream<>(infiniteStream);
Integer one = peelingInfiniteStream.getNext();
assertThat(one, equalTo(0));
Integer two = peelingInfiniteStream.getNext();
assertThat(two, equalTo(1));
Stream<Integer> limitedStream = peelingInfiniteStream.limit(3); // 2 3 4
int sumOf234 = limitedStream.mapToInt(x -> x.intValue()).sum();
assertThat(sumOf234, equalTo(2 + 3 + 4));
}
I did the following. The original stream does get closed, but a new stream which behaves exactly like the old stream is created.
You will need com.google.common.collect.Iterators from guava.
import static com.google.common.collect.Iterators.concat;
import static com.google.common.collect.Iterators.singletonIterator;
import static java.util.Spliterators.spliteratorUnknownSize;
import static java.util.stream.StreamSupport.stream;
private <T> Stream<T> peekFirst(Stream<T> originalStream){
//This closes the original Stream
Iterator<T> originalIterator = originalStream.iterator();
if (!originalIterator.hasNext()) {
return Stream.of();
}
T firstElement = originalIterator.next();
doSomethingWithFirstElement(firstElement);
Iterator<T> newIterator = concat(
singletonIterator(firstElement),
originalIterator);
return stream(
spliteratorUnknownSize(newIterator, 0),
originalStream.isParallel());
}

Categories

Resources