Consider following snippet:
private List<User> getUsers() throws TasteException {
final int MAX_USERS = 100;
List<User> userList = new ArrayList<>(MAX_USERS);
dataModel.getUserIDs().forEachRemaining(userId -> {
if (userList.size() == 100) {
// stop
}
userList.add(new User(userId));
});
return userList;
}
break or return is not working here. What can I do?
The only way to stop the iteration early is to throw an exception. Using exceptions for control flow isn't advised, so I would use Stream.limit, .map, and .collect:
private List<User> getUsers() throws TasteException {
final int MAX_USERS = 100;
return dataModel.getUserIDs()
.stream()
.limit(MAX_USERS)
.map(userId -> new User(userId))
.collect(Collectors.toList());
}
If getUserIDs can't be changed to return Collection you can convert to a Spliterator first:
private List<User> getUsers() throws TasteException {
final int MAX_USERS = 10;
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(dataModel.getUserIDs(), 0), false)
.limit(MAX_USERS)
.map(userId -> new User(userId))
.collect(Collectors.toList());
}
You can 'emulate' a break; adding an if for a boolean check at start of the foreach lambda body, before doing any intensive operation
Note that I used an final Map<Boolean> to hold the boolean flag found as it's a way to declare a boolean 'variable' outside the lambda (you know, it has to be 'final') but be able to set its value in the loop
boolean containsSecret(Iterable<String> values) {
final Map<String, Boolean> scopedLambdaBooleans = new HashMap<String, Boolean>();
scopedLambdaBooleans.put("found", false);
values.forEach(s -> {
if (scopedLambdaBooleans.get("found")) {
return; //just the overhead of a boolean if but a continue before any iteration is very near to the break; performance
}
//Logger.getAnonymousLogger().info(s);
if (secret.equals(s)) {
scopedLambdaBooleans.put("found", true);
}
});
return scopedLambdaBooleans.get("found");
}
The overhead is just a boolean if check at start of any iteration
If you fell guilty for having added an if check, you can compensate getting rid of the internal if:
boolean containsSecretNoInternalIf(Iterable<String> values) {
final Map<String, Boolean> scopedLambdaBooleans = new HashMap<String, Boolean>();
scopedLambdaBooleans.put("found", false);
values.forEach(s -> {
if (scopedLambdaBooleans.get("found")) {
return; //just the overhead of a boolean if but a continue before any iteration is very near to the break; performance
}
Logger.getAnonymousLogger().info(s);
scopedLambdaBooleans.put("found", secret.equals(s));
});
return scopedLambdaBooleans.get("found");
}
Anyway that's writing a boolean 'bit' in memory at any iteration before the finding, I don't know if really better than an 'if' (is the java 'if check' on a .equals using a bit of memory to execute itself or directly cpu registers? uhm.. being on a jvm we should think it like 'Stack vs. Heap' and yes, I think on modern jvm with JIT compilers Stack has optimizations to use directly cpu registers )
Consider using the streams properly, it seems like you want:
dataModel.getUserIDs().stream()
.limit(100)
.forEach(userId -> userList.add(new User(userId)));
This will obtain a stream of the first 100 items and perform an action on them. I cannot give a more detailed answer as I do not know the signature of dataModel.getUserIDs().
Control flow (break, early return) - In the forEach examples above, a traditional continue is possible by placing a "return;" statement within the lambda. However, there is no way to break out of the loop or return a value as the result of the containing method from within the lambda. For example:
final String secret = "foo";
boolean containsSecret(Iterable<String> values) {
values.forEach(s -> {
if (secret.equals(s)) {
??? // want to end the loop and return true, but can't
}
});
}
To see more here is the link : http://www.techempower.com/blog/2013/03/26/everything-about-java-8/
In order to break/exit from forEachRemaining of Scanner instance, close the console input as below once the exit condition is met.
scanner.forEachRemaining(s -> {
if(s.equals("exit")) {
try {
System.in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
parkingLot.execute(s.trim().split(" "));
});
Related
The code below compiles and does its job, however lets say I needed to added another 100 if statements that uses a reference. Whats the most efficient way to write multiple if statements?
public String getForceDetails(String ref) {
if (ref.equals("IW1")) {
setupForces();
return (ForceDetails.get(0).toString());
} else if (ref.equals("SS2")) {
setupForces();
return (ForceDetails.get(1).toString());
} else if (ref.equals("WB3")) {
setupForces();
return (ForceDetails.get(2).toString());
} else if (ref.equals("IW4")) {
setupForces();
return (ForceDetails.get(3).toString());
} else if (ref.equals("WB5")) {
setupForces();
return (ForceDetails.get(4).toString());
} else if (ref.equals("SS6")) {
setupForces();
return (ForceDetails.get(5).toString());
} else if (ref.equals("SS7")) {
setupForces();
return (ForceDetails.get(6).toString());
} else if (ref.equals("WB9")) {
setupForces();
return (ForceDetails.get(7).toString());
} else if (ref.equals("IW10")) {
setupForces();
return (ForceDetails.get(8).toString());
} else {
return "\nNo such force";
}
}
private void setupForces()
{
ForceDetails.add(new starShip("IW1","Twisters",200,200,ForceState.DOCKED,10,0,0,false));
ForceDetails.add(new starShip("SS2","Enterprise",300,200,ForceState.DOCKED,0,10,20,false));
ForceDetails.add(new starShip("WB3","Droop",300,100,ForceState.DOCKED,0,0,0,false));
ForceDetails.add(new starShip("IW4","Wingers",200,400,ForceState.DOCKED,20,0,0,false));
ForceDetails.add(new starShip("WB5","Hang",400,300,ForceState.DOCKED,0,0,0,true));
ForceDetails.add(new starShip("SS6","Voyager",450,200,ForceState.DOCKED,0,15,10,false));
ForceDetails.add(new starShip("SS7","Explorer",120, 65,ForceState.DOCKED,0,4,5,false));
ForceDetails.add(new starShip("WB9","Hover",300,400,ForceState.DOCKED,0,0,0,false));
ForceDetails.add(new starShip("IW10","Flyers",200,100,ForceState.DOCKED,5,0,0,false));
}
The obvious choice would be a switch statement over ref:
switch (ref) {
case "IW1":
setupForces();
return (ForceDetails.get(0).toString());
break;
case "SS2":
setupForces();
return (ForceDetails.get(1).toString());
break;
// etc.
}
If the code to execute always looks the like this (calling setupForces() and getting the n-th element of ForceDetails) you could also use a map that lets you retrieve n (Map<String, Integer>) which you populate with key-value-pairs like "IW1"->0 and "SS2"->1 etc.
The map solution also has the charme that you do not need to repeat the code that is basically equal for all cases which would be rather inconvenient if you have to change this later.
Well there is no inbuilt solution to that. What you can do is create a Map of condition -> result and return the value to the key.
Map<String, String> mapCondToRes = new HashMap<>();
public String getForceDetails(String ref) {
setupForces();
return mapCondToRes.get(ref);
}
You can check for validations and put more conditions very easily and elegantly.
In the existing code, each invocation of getForceDetails with a valid ref causes adding of 9 entries to a collection of starships ForceDetails. It is doubtful that this behaviour is intended, possibly a lazy initialization of ForceDetails was implied.
Next, to get rid of the multiple if statements using of the map is definitely more preferable than converting into switch statement and copying the same multiple calls to setupForces(). It could make sense to create a map Map<String, starship> instead of the list and populate it in setupForces (so there's no need to have a separate map of references to the index in the list):
Map<String, starShip> forces = new HashMap<>();
private void setupForces() {
forces.put("IW1", new starShip("IW1","Twisters",200,200,ForceState.DOCKED,10,0,0,false));
forces.put("SS2", new starShip("SS2","Enterprise",300,200,ForceState.DOCKED,0,10,20,false));
// ... add other starships mapped by their ids
}
public String getForceDetails(String ref) {
if (forces.isEmpty()) {
setupForces();
}
return Optional.ofNullable(forces.get(ref))
.map(starShip::toString)
.orElse("No such force found");
}
Use a java stream, you should read about them, you'll find it useful later as you progress on Java.
For the following code, I assume you have a getter for your "key" values inside your starShip class ("IW1", "SS2", "WB3"...).
This code also assumes that you cannot change your current List approach, If you can, a Map would be a even better.
private static final String NO_FORCE = "\nNo such force";
public String getForceDetails(String ref) {
String result = ForceDetails.stream() // <-- It's even faster if you use `parallelStream` however is known to have non-thread-safe issues
.filter(starShipItem -> Objects.equals(starShipItem.getKey(), ref))
.map(String::valueOf).findFirst()
.orElse(NO_FORCE)
;
if (NO_FORCE.equals(result)) {
return NO_FORCE;
}
setupForces();
return result;
}
Also, I recommend you to take a look at hackerrank challenges, you'll learn a lot more there.
I have this:
Stream<CompletableFuture<List<Item>>>
how can I convert it to
Stream<CompletableFuture<Item>>
Where: the second stream is comprised of each and all the Items inside each of the lists in the first stream.
I looked into thenCompose but that solves a completely different problem which is also referred to as "flattening".
How can this be done efficiently, in a streaming fashion, without blocking or prematurely consuming more stream items than necessary?
Here is my best attempt so far:
ExecutorService pool = Executors.newFixedThreadPool(PARALLELISM);
Stream<CompletableFuture<List<IncomingItem>>> reload = ... ;
#SuppressWarnings("unchecked")
CompletableFuture<List<IncomingItem>> allFutures[] = reload.toArray(CompletableFuture[]::new);
CompletionService<List<IncomingItem>> queue = new ExecutorCompletionService<>(pool);
for(CompletableFuture<List<IncomingItem>> item: allFutures) {
queue.submit(item::get);
}
List<IncomingItem> THE_END = new ArrayList<IncomingItem>();
CompletableFuture<List<IncomingItem>> ender = CompletableFuture.allOf(allFutures).thenApply(whatever -> {
queue.submit(() -> THE_END);
return THE_END;
});
queue.submit(() -> ender.get());
Iterable<List<IncomingItem>> iter = () -> new Iterator<List<IncomingItem>>() {
boolean checkNext = true;
List<IncomingItem> next = null;
#Override
public boolean hasNext() {
if(checkNext) {
try {
next = queue.take().get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
checkNext = false;
}
if(next == THE_END || next == null) {
return false;
}
else {
return true;
}
}
#Override
public List<IncomingItem> next() {
if(checkNext) {
hasNext();
}
if(!hasNext()) {
throw new IllegalStateException();
}
checkNext = true;
return next;
}
};
Stream<IncomingItem> flat = StreamSupport.stream(iter.spliterator(), false).flatMap(List::stream);
This works at first, unfortunately, it has a fatal bug: the resulting stream seems to terminate prematurely, before retrieving all the items.
As I wrote in my comment, this is impossible.
Consider a some arbitrary service, which will return a CompletableFuture<Integer>:
CompletableFuture<Integer> getDiceRoll();
I can now convert this CompletableFuture<Integer> to a Stream<CompletableFuture<List<Object>>> without any problem:
Stream<CompletableFuture<List<Object>>> futureList = Stream.of(getDiceRoll().thenApply(n -> List.of(new Object[n])));
Let's suppose there would be a general way to turn a Stream<CompletableFuture<List<T>>> into a Stream<CompletableFuture<T>>:
<T> Stream<CompletableFuture<T> magic(Stream<CompletableFuture<List<T>>> arg);
Then I can do the following:
int diceRoll = magic(Stream.of(getDiceRoll().thenApply(n -> List.of(new Object[n])))).count();
Wait, what?
I am now able to get an arbitrary integer out of a CompletableFuture.
Which means, with some engineering effort I can get all the information out of a CompletableFuture - after all, memory is just some numbers.
So we have to conclude that a method like magic can not exist, without violating the time fabric.
And this is the answer: There is no such method, because it can not exist.
Agreed with Johannes Kuhn. You can't know Futures's state while it's still executing and thus can not convert from Stream<CompletableFuture<List>>
to Stream<CompletableFuture> .
Although the output of stream can be merged using following piece of code -
java Stream<CompletableFuture<List<Item>>> to java List<Item> or
java List<CompletableFuture<List<AuditRecord>>> to java List<Item>
List<Item> output = input.map(CompletableFuture::join).collect(toList()).stream()
.flatMap(Collection::stream).collect(toList());
I understand you can't return from a ifPresent() so this example does not work:
public boolean checkSomethingIfPresent() {
mightReturnAString().ifPresent((item) -> {
if (item.equals("something")) {
// Do some other stuff like use "something" in API calls
return true; // Does not compile
}
});
return false;
}
Where mightReturnAString() could return a valid string or an empty optional. What I have done that works is:
public boolean checkSomethingIsPresent() {
Optional<String> result = mightReturnAString();
if (result.isPresent()) {
String item = result.get();
if (item.equals("something") {
// Do some other stuff like use "something" in API calls
return true;
}
}
return false;
}
which is longer and does not feel much different to just checking for nulls in the first place. I feel like there must be a more succinct way using Optional.
I think all you're looking for is simply filter and check for the presence then:
return result.filter(a -> a.equals("something")).isPresent();
How about mapping to a boolean?
public boolean checkSomethingIfPresent() {
return mightReturnAString().map(item -> {
if (item.equals("something")) {
// Do some other stuff like use "something" in API calls
return true; // Does not compile
}
return false; // or null
}).orElse(false);
}
While #nullpointer and #Ravindra showed how to merge the Optional with another condition, you'll have to do a bit more to be able to call APIs and do other stuff as you asked in the question. The following looks quite readable and concise in my opinion:
private static boolean checkSomethingIfPresent() {
Optional<String> str = mightReturnAString();
if (str.filter(s -> s.equals("something")).isPresent()) {
//call APIs here using str.get()
return true;
}
return false;
}
A better design would be to chain methods:
private static void checkSomethingIfPresent() {
mightReturnFilteredString().ifPresent(s -> {
//call APIs here
});
}
private static Optional<String> mightReturnFilteredString() {
return mightReturnAString().filter(s -> s.equals("something"));
}
private static Optional<String> mightReturnAString() {
return Optional.of("something");
}
The ideal solution is “command-query separation”: Make one method (command) for doing something with the string if it is present. And another method (query) to tell you whether it was there.
However, we don’t live an ideal world, and perfect solutions are never possible. If in your situation you cannot separate command and query, my taste is for the idea already presented by shmosel: map to a boolean. As a detail I would use filter rather than the inner if statement:
public boolean checkSomethingIfPresent() {
return mightReturnAString().filter(item -> item.equals("something"))
.map(item -> {
// Do some other stuff like use "something" in API calls
return true; // (compiles)
})
.orElse(false);
}
What I don’t like about it is that the call chain has a side effect, which is not normally expected except from ifPresent and ifPresentOrElse (and orElseThrow, of course).
If we insist on using ifPresent to make the side effect clearer, that is possible:
AtomicBoolean result = new AtomicBoolean(false);
mightReturnAString().filter(item -> item.equals("something"))
.ifPresent(item -> {
// Do some other stuff like use "something" in API calls
result.set(true);
});
return result.get();
I use AtomicBoolean as a container for the result since we would not be allowed to assign to a primitive boolean from within the lambda. We don’t need its atomicity, but it doesn’t harm either.
Link: Command–query separation on Wikipedia
By the way if you really want to get value from Optional, use:
Optional<User> user = service.getCurrentUset();
return user.map(User::getId);
With Java 8, I have this code:
if(element.exist()){
// Do something
}
I want to convert to lambda style,
element.ifExist(el -> {
// Do something
});
with an ifExist method like this:
public void ifExist(Consumer<Element> consumer) {
if (exist()) {
consumer.accept(this);
}
}
But now I have else cases to call:
element.ifExist(el -> {
// Do something
}).ifNotExist(el -> {
// Do something
});
I can write a similar ifNotExist, and I want they are mutually exclusive (if the exist condition is true, there is no need to check ifNotExist, because sometimes, the exist() method takes so much workload to check), but I always have to check two times. How can I avoid that?
Maybe the "exist" word make someone misunderstand my idea. You can imagine that I also need some methods:
ifVisible()
ifEmpty()
ifHasAttribute()
Many people said that this is bad idea, but:
In Java 8 we can use lambda forEach instead of a traditional for loop. In programming for and if are two basic flow controls. If we can use lambda for a for loop, why is using lambda for if bad idea?
for (Element element : list) {
element.doSomething();
}
list.forEach(Element::doSomething);
In Java 8, there's Optional with ifPresent, similar to my idea of ifExist:
Optional<Elem> element = ...
element.ifPresent(el -> System.out.println("Present " + el);
And about code maintenance and readability, what do you think if I have the following code with many repeating simple if clauses?
if (e0.exist()) {
e0.actionA();
} else {
e0.actionB();
}
if (e1.exist()) {
e0.actionC();
}
if (e2.exist()) {
e2.actionD();
}
if (e3.exist()) {
e3.actionB();
}
Compare to:
e0.ifExist(Element::actionA).ifNotExist(Element::actionB);
e1.ifExist(Element::actionC);
e2.ifExist(Element::actionD);
e3.ifExist(Element::actionB);
Which is better? And, oops, do you notice that in the traditional if clause code, there's a mistake in:
if (e1.exist()) {
e0.actionC(); // Actually e1
}
I think if we use lambda, we can avoid this mistake!
As it almost but not really matches Optional, maybe you might reconsider the logic:
Java 8 has a limited expressiveness:
Optional<Elem> element = ...
element.ifPresent(el -> System.out.println("Present " + el);
System.out.println(element.orElse(DEFAULT_ELEM));
Here the map might restrict the view on the element:
element.map(el -> el.mySpecialView()).ifPresent(System.out::println);
Java 9:
element.ifPresentOrElse(el -> System.out.println("Present " + el,
() -> System.out.println("Not present"));
In general the two branches are asymmetric.
It's called a 'fluent interface'. Simply change the return type and return this; to allow you to chain the methods:
public MyClass ifExist(Consumer<Element> consumer) {
if (exist()) {
consumer.accept(this);
}
return this;
}
public MyClass ifNotExist(Consumer<Element> consumer) {
if (!exist()) {
consumer.accept(this);
}
return this;
}
You could get a bit fancier and return an intermediate type:
interface Else<T>
{
public void otherwise(Consumer<T> consumer); // 'else' is a keyword
}
class DefaultElse<T> implements Else<T>
{
private final T item;
DefaultElse(final T item) { this.item = item; }
public void otherwise(Consumer<T> consumer)
{
consumer.accept(item);
}
}
class NoopElse<T> implements Else<T>
{
public void otherwise(Consumer<T> consumer) { }
}
public Else<MyClass> ifExist(Consumer<Element> consumer) {
if (exist()) {
consumer.accept(this);
return new NoopElse<>();
}
return new DefaultElse<>(this);
}
Sample usage:
element.ifExist(el -> {
//do something
})
.otherwise(el -> {
//do something else
});
You can use a single method that takes two consumers:
public void ifExistOrElse(Consumer<Element> ifExist, Consumer<Element> orElse) {
if (exist()) {
ifExist.accept(this);
} else {
orElse.accept(this);
}
}
Then call it with:
element.ifExistOrElse(
el -> {
// Do something
},
el -> {
// Do something else
});
The problem
(1) You seem to mix up different aspects - control flow and domain logic.
element.ifExist(() -> { ... }).otherElementMethod();
^ ^
control flow method business logic method
(2) It is unclear how methods after a control flow method (like ifExist, ifNotExist) should behave. Should they be always executed or be called only under the condition (similar to ifExist)?
(3) The name ifExist implies a terminal operation, so there is nothing to return - void. A good example is void ifPresent(Consumer) from Optional.
The solution
I would write a fully separated class that would be independent of any concrete class and any specific condition.
The interface is simple, and consists of two contextless control flow methods - ifTrue and ifFalse.
There can be a few ways to create a Condition object. I wrote a static factory method for your instance (e.g. element) and condition (e.g. Element::exist).
public class Condition<E> {
private final Predicate<E> condition;
private final E operand;
private Boolean result;
private Condition(E operand, Predicate<E> condition) {
this.condition = condition;
this.operand = operand;
}
public static <E> Condition<E> of(E element, Predicate<E> condition) {
return new Condition<>(element, condition);
}
public Condition<E> ifTrue(Consumer<E> consumer) {
if (result == null)
result = condition.test(operand);
if (result)
consumer.accept(operand);
return this;
}
public Condition<E> ifFalse(Consumer<E> consumer) {
if (result == null)
result = condition.test(operand);
if (!result)
consumer.accept(operand);
return this;
}
public E getOperand() {
return operand;
}
}
Moreover, we can integrate Condition into Element:
class Element {
...
public Condition<Element> formCondition(Predicate<Element> condition) {
return Condition.of(this, condition);
}
}
The pattern I am promoting is:
work with an Element;
obtain a Condition;
control the flow by the Condition;
switch back to the Element;
continue working with the Element.
The result
Obtaining a Condition by Condition.of:
Element element = new Element();
Condition.of(element, Element::exist)
.ifTrue(e -> { ... })
.ifFalse(e -> { ... })
.getOperand()
.otherElementMethod();
Obtaining a Condition by Element#formCondition:
Element element = new Element();
element.formCondition(Element::exist)
.ifTrue(e -> { ... })
.ifFalse(e -> { ... })
.getOperand()
.otherElementMethod();
Update 1:
For other test methods, the idea remains the same.
Element element = new Element();
element.formCondition(Element::isVisible);
element.formCondition(Element::isEmpty);
element.formCondition(e -> e.hasAttribute(ATTRIBUTE));
Update 2:
It is a good reason to rethink the code design. Neither of 2 snippets is great.
Imagine you need actionC within e0.exist(). How would the method reference Element::actionA be changed?
It would be turned back into a lambda:
e0.ifExist(e -> { e.actionA(); e.actionC(); });
unless you wrap actionA and actionC in a single method (which sounds awful):
e0.ifExist(Element::actionAAndC);
The lambda now is even less 'readable' then the if was.
e0.ifExist(e -> {
e0.actionA();
e0.actionC();
});
But how much effort would we make to do that? And how much effort will we put into maintaining it all?
if(e0.exist()) {
e0.actionA();
e0.actionC();
}
If you are performing a simple check on an object and then executing some statements based on the condition then one approach would be to have a Map with a Predicate as key and desired expression as value
for example.
Map<Predicate<Integer>,Supplier<String>> ruleMap = new LinkedHashMap <Predicate<Integer>,Supplier<String>>(){{
put((i)-> i<10,()->"Less than 10!");
put((i)-> i<100,()->"Less than 100!");
put((i)-> i<1000,()->"Less than 1000!");
}};
We could later stream the following Map to get the value when the Predicate returns true which could replace all the if/else code
ruleMap.keySet()
.stream()
.filter((keyCondition)->keyCondition.test(numItems,version))
.findFirst()
.ifPresent((e)-> System.out.print(ruleMap.get(e).get()));
Since we are using findFirst() it is equivalent to if/else if /else if ......
How can I express this with java8 streaming-API?
I want to perform itemConsumer for every item of a stream. If there
are no items I want to perform emptyAction.
Of course I could write something like this:
Consumer<Object> itemConsumer = System.out::println;
Runnable emptyAction = () -> {System.out.println("no elements");};
Stream<Object> stream = Stream.of("a","b"); // or Stream.empty()
List<Object> list = stream.collect(Collectors.toList());
if (list.isEmpty())
emptyAction.run();
else
list.stream().forEach(itemConsumer);
But I would prefer to avoid any Lists.
I also thought about setting a flag in a peek method - but that flag would be non-final and therefore not allowed. Using a boolean container also seems to be too much of a workaround.
You could coerce reduce to do this. The logic would be to reduce on false, setting the value to true if any useful data is encountered.
The the result of the reduce is then false then no items have been encountered. If any items were encountered then the result would be true:
boolean hasItems = stream.reduce(false, (o, i) -> {
itemConsumer.accept(i);
return true;
}, (l, r) -> l | r);
if (!hasItems) {
emptyAction.run();
}
This should work fine for parallel streams, as any stream encountering an item would set the value to true.
I'm not sure, however, that I like this as it's a slightly obtuse use of the reduce operation.
An alternative would be to use AtomicBoolean as a mutable boolean container:
final AtomicBoolean hasItems = new AtomicBoolean(false);
stream.forEach(i -> {
itemConsumer.accept(i);
hasItems.set(true);
});
if (!hasItems.get()) {
emptyAction.run();
}
I don't know if I like that more or less however.
Finally, you could have your itemConsumer remember state:
class ItemConsumer implements Consumer<Object> {
private volatile boolean hasConsumedAny;
#Override
public void accept(Object o) {
hasConsumedAny = true;
//magic magic
}
public boolean isHasConsumedAny() {
return hasConsumedAny;
}
}
final ItemConsumer itemConsumer = new ItemConsumer();
stream.forEach(itemConsumer::accept);
if (!itemConsumer.isHasConsumedAny()) {
emptyAction.run();
}
This seems a bit neater, but might not be practical. So maybe a decorator pattern -
class ItemConsumer<T> implements Consumer<T> {
private volatile boolean hasConsumedAny;
private final Consumer<T> delegate;
ItemConsumer(final Consumer<T> delegate) {
this.delegate = delegate;
}
#Override
public void accept(T t) {
hasConsumedAny = true;
delegate.accept(t);
}
public boolean isHasConsumedAny() {
return hasConsumedAny;
}
}
final ItemConsumer<Object> consumer = new ItemConsumer<Object>(() -> /** magic **/);
TL;DR: something has to remember whether you encountered anything during the consumption of the Stream, be it:
the Stream itself in case of reduce;
AtomicBoolean; or
the consumer
I think the consumer is probably best placed, from a logic point of view.
A solution without any additional variables:
stream.peek(itemConsumer).reduce((a, b) -> a).orElseGet(() -> {
emptyAction.run();
return null;
});
Note that if the stream is parallel, then itemConsumer could be called simultaneously for different elements in different threads (like in forEach, not in forEachOrdered). Also this solution will fail if the first stream element is null.
There’s a simple straight-forward solution:
Spliterator<Object> sp=stream.spliterator();
if(!sp.tryAdvance(itemConsumer))
emptyAction.run();
else
sp.forEachRemaining(itemConsumer);
You can even keep parallel support for the elements after the first, if you wish:
Spliterator<Object> sp=stream.parallel().spliterator();
if(!sp.tryAdvance(itemConsumer))
emptyAction.run();
else
StreamSupport.stream(sp, true).forEach(itemConsumer);
In my opinion, it is much easier to understand as a reduce based solution.
You could do this:
if(stream.peek(itemConsumer).count() == 0){
emptyAction.run();
}
But it seems that count may be changed to skip the peek if it knows the size of the Stream in Java 9 (see here), so if you want it to work in the future you could use:
if(stream.peek(itemConsumer).mapToLong(e -> 1).sum() == 0){
emptyAction.run();
}
Another attempt to use reduce:
Stream<Object> stream = Stream.of("a","b","c");
//Stream<Object> stream = Stream.empty();
Runnable defaultRunnable = () -> System.out.println("empty Stream");
Consumer<Object> printConsumer = System.out::println;
Runnable runnable = stream.map(x -> toRunnable(x, printConsumer)).reduce((a, b) -> () -> {
a.run();
b.run();
}).orElse(defaultRunnable);
runnable.run(); // prints a, b, c (or empty stream when it is empty)
// for type inference
static <T> Runnable toRunnable(T t, Consumer<T> cons){
return ()->cons.accept(t);
}
This approach does not use peek() which according to Javadoc "mainly exists to support debugging"