/*
* Copyright 2015 Petr Bouda
*
* 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 org.joyrest.stream;
import java.util.Optional;
import java.util.Spliterator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* Utility stream class which combines two elements and provides functions upon them.
* First object is always object from stream and the second object is
*
* @param <T> the first input element
* @param <U> the second input element
* @author pbouda
*/
public class BiStream<T, U> {
private final Stream<T> stream;
private final U object;
public BiStream(Stream<T> stream, U object) {
this.stream = stream;
this.object = object;
}
/**
* Factory method {@link BiStream} class
*
* @param stream stream objects
* @param obj object which is compared to objects from stream
* @param <T> type of the objects in stream
* @param <U> type of the compared object
* @return BiStream object
*/
public static <T, U> BiStream<T, U> of(Stream<T> stream, U obj) {
return new BiStream<>(stream, obj);
}
/**
* Compares the objects from stream to the injected object. If the rest of the stream equals null so exception is thrown.
*
* @param biPredicate which compare objects from stream and injected object
* @param e exception which will be thrown if the stream equals {@code null}
* @return BiStream object
*/
public BiStream<T, U> throwIfNull(BiPredicate<? super T, ? super U> biPredicate, Supplier<? extends RuntimeException> e) {
Predicate<T> predicate = (t) -> biPredicate.test(t, object);
return nonEmptyStream(stream.filter(predicate), e);
}
public Optional<T> findAny() {
return stream.findAny();
}
private BiStream<T, U> nonEmptyStream(Stream<T> stream, Supplier<? extends RuntimeException> e) {
Spliterator<T> spliterator = stream.spliterator();
Stream<T> localStream = StreamSupport.stream(new BiStreamSpliterator<>(spliterator, e), false);
return of(localStream, object);
}
private static final class BiStreamSpliterator<T> implements Spliterator<T> {
private final Spliterator<T> it;
private final Supplier<? extends RuntimeException> e;
boolean seen;
private BiStreamSpliterator(Spliterator<T> it, Supplier<? extends RuntimeException> e) {
this.it = it;
this.e = e;
}
@Override
public boolean tryAdvance(Consumer<? super T> action) {
boolean r = it.tryAdvance(action);
if (!seen && !r) {
throw e.get();
}
seen = true;
return r;
}
@Override
public Spliterator<T> trySplit() {
return null;
}
@Override
public long estimateSize() {
return it.estimateSize();
}
@Override
public int characteristics() {
return it.characteristics();
}
}
}