Related
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)
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;
}
}
I'm not entirely comfortable with generics and thus haven't found a solution to this yet. I have these three methods:
public static List<ObjectA> objectAAsList(ObjectA ... items) {
return new ArrayList<>(Arrays.asList(items));
}
public static List<ObjectB> objectBAsList(ObjectB ... items) {
return new ArrayList<>(Arrays.asList(items));
}
public static List<ObjectC> objectCAsList(ObjectC ... items) {
return new ArrayList<>(Arrays.asList(items));
}
How can I create a single method that takes a vararg of T (or something) and creates an ArrayList of it?
Just replace your type with a type variable:
public static <T> List<T> genericAsList(T ... items) {
return new ArrayList<>(Arrays.asList(items));
}
Note that you could look at how Arrays.asList is declared, since it does largely the same thing, from a type perspective.
I think a Function is a better approach than a static method. You can define a Function :
public class VarArgsToList<T> implements Function<T[], List<T>> {
#Override
public List<T> apply(final T... items) {
return new ArrayList<>(Arrays.asList(items));
}
}
and apply it wherever:
public static void main(final String... arg) {
...
final List<String> list1 = new VarArgsToList<String>().apply(arg);
...
final List<MyObject> list2 = new VarArgsToList<MyObject>().apply(myObject1, myObject2, myObject3);
...
}
This is an aritmetic expression evaluator that uses the interpreter GOF pattern, BinaryOp is a non terminal expression.
public class BinaryOP<T> implements Expression<T> {
private Expression<T> e1;
private Expression<T> e2;
private BiFunction<Expression<T>, Expression<T>, T> f;
public BinaryOp(Expression<T> e1, Expression<T> e2,
BiFunction<Expression<T>, Expression<T>, T> f){
this.e1 = e1; this.e2 = e2; this.f = f;
}
#Override
public <T> T interpret(IContext context){
return (T)f.apply(e1, e2);
}
}
And variable is the terminal expression.
public class Variable<T> implements Expression<T> {
private T v;
public Variable(T v){
this.v = v;
}
#Override
public <T> T interpret(IContext context){
return (T)context.recognize(v);
}
}
When defining the BiFunction sum I get an error when using the lambda, an error on its parameters, if a and b are of type expression and the result returns an integer ¿Why is this error?.
public class AritmeticInterpreter
{
public static void main(String[] args) {
IContext<Integer> ctxArimetic = value -> value;
BiFunction<Expression<Integer>, Expression<Integer>, Integer> sum
//Error = incompatible types: incompatible parameter types in lambda expression
= (a, b, result) -> {
return (Integer)a.interpret(ctxArimetic) + (Integer)b.interpret(ctxArimetic);
};
}
}
What is causing this error, has to be the return type another expression?
if I change the interpret method return type to expression, I wouldn't be able to sum two expressions a and b like this:
(a, b) -> a + b
because they are not Integers.
and well, this no part of the title but, ¿can I get rid of casting interpret on method? I know that java compiler erases the generic type but, ¿is there a way?
Update:
Here is the Expression interface.
public interface Expression<T> {
public <T> T interpret(IContext context);
}
Acording to JB Nizet comment and this example I found that I just have to use a and b as arguments in the lambda.
Here is the correct code.
public static void main(String[] args) {
IContext<Integer> ctxArimetic = value -> value;
BiFunction<Expression<Integer>, Expression<Integer>, Integer> sum
= (a, b) -> {
return a.interpret(ctxArimetic) + b.interpret(ctxArimetic);
};
}
and for the last question.
on BinaryOP class i make this change:
#Override
public T interpret(IContext<T> context){
return f.apply(e1, e2);
}
and on the Expression Interface:
public interface Expression<T> {
public T interpret(IContext<T> context);
}
This error was because I parametrized the interpret method, and this allows the method to return any object. I remember that the compiler output the error "T#2 is different from type T#1" T#2 was the generic parameter <T> on interpret method and T#1 was the generic type on the class BinaryOp<T>.
I didn't Know how to use lambdas and generics correctly.
Update: Fix some errors, I changed
public T interpret(IContext context);
To
public T interpret(IContext<T> context);
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());
}