The following options are available:
- Use
StreamEx
library (maven repo) and its quasi-intermediate operation StreamEx::ifEmpty:
import one.util.streamex.StreamEx;
// ...
String msgSearch = "commit message";
StreamEx.of(commits.values())
.filter(c -> c.getLogMessage().compareTo(msgSearch) == 0)
.ifEmpty("no commit message found: " + msgSearch)
.map(Commit::getSha)
.forEach(System.out::println);
- Plus: very concise and clean, single run
- Minus: use of a 3rd-party lib
- Check the contents of the stream using short-circuiting match without redundant collecting into a list just to check if it's empty
if (commits.values().stream()
.map(Commit::getLogMessage) // equals should be equivalent to compareTo == 0
.anyMatch(msgSearch::equals)
) {
commits.values().stream()
.filter(c -> c.getLogMessage().compareTo(msgSearch) == 0)
.map(Commit::getSha)
.forEach(System.out::println);
} else {
System.out.println("no commit message found: " + msgSearch);
}
- Plus: using standard API (no 3-rd party) without side-effect
- Minuses: too verbose, in the worst case (long list with the matching element in the end) double iteration of the stream
- Use effectively final variable and its setting from the stream as a side effect.
Disclaimer: usage of stateful streams and side effects are not recommended in general:
The best approach is to avoid stateful behavioral parameters to stream operations entirely...
Side-effects in behavioral parameters to stream operations are, in general, discouraged, as they can often lead to unwitting violations of the statelessness requirement, as well as other thread-safety hazards.
A small number of stream operations, such as forEach()
and peek()
, can operate only via side-effects; these should be used with care
Thus, if AtomicBoolean
is carefully selected as a thread-safe and fast container of a boolean value for found
flag, which is only set to true
from inside the stream (never reset), the following solution may be offered and the risks of safety and performance are mitigated:
// effectively final and thread-safe container boolean
AtomicBoolean found = new AtomicBoolean();
commits.values().stream()
.filter(c -> c.getLogMessage().compareTo(commitMessageToSearch) == 0)
.map(Commit::getSha)
.forEach(sha -> {
found.set(true);
System.out.println(sha);
});
if (!found.get()) {
System.out.println("none found");
}
- Plus: using standard API (no 3rd-party library), single run, no redundant collection
- Minus: using side-effect, discouraged by purists, just mimics of
for-each
loop