I need to convert Stream<Optional<Integer>> to Optional<Stream<Integer>>.
The output Optional<Stream<Integer>> should be an empty value when at least one value ofStream<Optional<Integer>> is empty.
Do you know any functional way to solve the problem? I tried to use collect method, but without success.
Well, the tricky thing here is that if you're just given a Stream, you can only use it once.
To be stateless and avoid redundant copying, one way is to just catch NoSuchElementException:
static <T> Optional<Stream<T>> invert(Stream<Optional<T>> stream) {
try {
return Optional.of(
stream.map(Optional::get)
.collect(Collectors.toList())
.stream());
} catch (NoSuchElementException e) {
return Optional.empty();
}
}
A simple inversion would be:
static <T> Optional<Stream<T>> invert(Stream<Optional<T>> stream) {
return Optional.of(stream.map(Optional::get));
}
But to find out if it contains an empty element, you need to actually traverse it which also consumes it.
If you're given the source of the stream, you can traverse it without collecting it:
static <T> Optional<Stream<T>> invert(
Supplier<Stream<Optional<T>>> supplier) {
// taking advantage of short-circuiting here
// instead of allMatch(Optional::isPresent)
return supplier.get().anyMatch(o -> !o.isPresent()) ?
Optional.empty() : Optional.of(supplier.get().map(Optional::get));
}
List<Optional<Integer>> myInts =
Arrays.asList(Optional.of(1), Optional.of(2), Optional.of(3));
Optional<Stream<Integer>> inverted = invert(myInts::stream);
That's probably a more interesting approach. (But it's prone to a race condition because the stream() is taken twice. If some other thread adds an empty element in between and gets away with it, we have a problem.)
Though this has already been answered yet to add to the list, with Java-9 introducing Optional.stream, this should be achievable as:
// initialized stream of optional
Stream<Optional<Integer>> so = Stream.empty();
// mapped stream of T
Stream<Integer> s = so.flatMap(Optional::stream);
// constructing optional from the stream
Optional<Stream<Integer>> os = Optional.of(s);
Similar to Radiodef's answer, though this one avoids the exception handling and the intermediate list.
private static <T> Optional<Stream<T>> invertOptional(Stream<Optional<T>> input) {
return input.map(integer -> integer.map(Stream::of))
.collect(Collectors.reducing((l, r) -> l.flatMap(lv -> r.map(rv -> Stream.concat(lv, rv)))))
.orElse(Optional.empty());
}
The way this works is it maps to a Stream of Optional Streams of T. The Optional.map is used in this case, so each one of the Optional<Stream<T>> items in the resultant stream is a either a Stream of 1, or an empty Optional.
Then it collects these streams by reducing them together. the l.flatMap will return an empty Optional if l is empty or the r.map returns an empty. if r.map isn't empty, it calls the Stream.concat, which combines the left and right stream values.
The whole collect reduction produces an Optional<Optional<Stream<T>>>, so we narrow that down with the .orElse(Optional.empty)
Note: Code is tested, and appears to work. The unspecified "edge case" of an empty input Stream is treated as an an empty Optional, but can be easily changed.
final Stream<Optional<Integer>> streamOfInts = Stream.of(Optional.of(1), Optional.of(2), Optional.of(3), Optional.of(4), Optional.of(5));
// false - list of Optional.empty(); true -> list of Optional.of(Integer)
final Map<Boolean, List<Optional<Integer>>> collect = streamOfInts.collect(Collectors.partitioningBy(Optional::isPresent));
final Function<List<Optional<Integer>>, Stream<Integer>> mapToStream = List->List.stream().filter(o->o.isPresent()).map(o->o.get());
Optional<Stream<Integer>> result = Optional
.of(Optional.of(collect.get(false)).filter(list->list.size()>0).orElse(collect.get(true)))
.filter(list->list.size()>0)
.filter(list->list.get(0).isPresent())
.map(mapToStream)
.map(Optional::of)
.orElse(Optional.empty());
Related
I have the following method which is working fine. I am trying to accomplish everything and get the value inside that Optional stream
without having to do the additional if check. Is it possible to map and get the Result object at index 0? Please advice thanks.
public String getData(HttpEntity<Request> request, String endPoint){
ResponseEntity<Reponse> response =
template.exchange(endPoint, HttpMethod.POST, request, Reponse.class);
List<Result> results = Optional.ofNullable(response)
.map(ResponseEntity::getBody)
.map(Response::getQueryResult)
.map(QueryResult::getResults)
// getResults is an ArrayList of Result Objects. Could I get the Result Object at index 0 here?
// following that I plan to go .map(Result::getValue) here.
.orElse(null);
if(CollectionUtils.isNotEmpty(results)){
return results.get(0).getValue();
}
return null;
}
return Optional.ofNullable(response)
.map(ResponseEntity::getBody)
.map(Response::getQueryResult)
.map(QueryResult::getResults)
.filter(CollectionUtils::isNotEmpty)
.map(list -> list.get(0)) // hate this part :)
.map(Result::getValue)
.orElse(null);
If you are a fan of method references, and you find lambdas boring
return Optional.ofNullable(response)
.map(ResponseEntity::getBody)
.map(Response::getQueryResult)
.map(QueryResult::getResults)
.filter(CollectionUtils::isNotEmpty)
.map(List::iterator)
.map(Iterator::next)
.map(Result::getValue)
.orElse(null);
I showed it for educational reasons, I don't advocate it even though I like it.
Assuming that the ArrayList is never null:
.flatMap(r -> r.stream().findFirst())
This takes the list, streams it, gets an Optional with the first element (or an empty Optional if the list is empty. Lastly, since an Optional<Optional<Result>> isn't that useful, we use flatMap instead of map to collapse it into an Optional<Result>.
change that orElse to return an empty List and stream from there. In such a way you can invoke findFirst safely - as for an empty List it will return Optional::empty and from there - you either map it (in case you do have it) to Result::getValue or, in case such a List is not present - null, so it is exactly as your program flow.
...
.map(QueryResult::getResults)
.orElse(Collections.emptyList())
.stream()
.findFirst()
.map(Result::getValue)
.orElse(null);
I have a class where optionally a Comparator can be specified.
Since the Comparator is optional, I have to evaluate its presence and execute the same stream code, either with sorted() or without:
if(comparator != null) {
[...].stream().map()[...].sorted(comparator)[...];
} else {
[...].stream().map()[...];
}
Question:
Is there a more elegant way to do this without the code duplication?
Note:
A default Comparator is not an option, I just want to keep the original order of the values I am streaming.
Besides, the elements are already mapped at the point of sorting, so I can not somehow reference the root list of the stream, as I do not have the original elements anymore.
You can do something like this:
Stream<Something> stream = [...].stream().map()[...]; // preliminary processing
if(comparator != null) {
stream = stream.sorted(comparator); // optional sorting
}
stream... // resumed processing, which ends in some terminal operation (such as collect)
Another way would be to use Optional:
Stream<Whatever> stream = [...].stream().map()[...];
List<WhateverElse> result = Optional.ofNullable(comparator)
.map(stream::sorted)
.orElse(stream)
.[...] // <-- go on with the stream pipeline
.collect(Collectors.toList());
You could define a comparator of your type (I used E as a placeholder here) that will not change the order:
Comparator<E> NO_SORTING = (one, other) -> 0;
If the comparator field is an Optional of Comparator, you can then use
.sorted(comparator.orElse(NO_SORTING))
If you don't mind use third party library StreamEx
StreamEx(source).[...].chain(s -> comparator == null ? s : s.sorted(comparator)).[...];
You can accomplish this using an auxiliary function.
static <T, R> R applyFunction(T obj, Function<T, R> f) {
return f.apply(obj);
}
and
applyFunction([...].stream().map()[...],
stream -> comparator == null ? stream : stream.sorted(comparator))
[...];
You don't need to know intermediate stream type.
I have a loop which update an String object:
String result = "";
for (SomeObject obj: someObjectList) {
result = someMetohd(obj, result);
}
An implementation of someMethod is irrelevant:
private String someMethod(SomeObject obj, String result) {
result = result.concat(obj.toString());
return result;
}
And I want to use Stream instead a loop. How to implement it with Stream?
#SuppressWarnings("OptionalGetWithoutIsPresent")
String result = Stream.concat(Stream.of(""), someObjectList.stream())
.reduce(this::someMethod)
.get();
Your someMethod should be associative as specified in the documentation, however this is only important for parallel streams, while your code is explicitly sequential
As you always add to the result, you can consider it a first element of the stream and then use reduce method which will always merge first two elements - current result and next element
result has to be the first parameter of your someMethod
Because all elements in the stream have to be of the same type, while you have String result and SomeObject elements, you need to change the signature of someMethod to accept two Objects (and do the casts inside the method): private String someMethod(Object result, Object obj). This is the most ugly part of this solution.
You can inline the initial value of the result - no need to define result upfront
You might want to change this::someMethod depending on where this method is declared
Finally, you don't need to worry about handling Optional result, because the stream always has at least one element so it's safe to just call get()
final StringBuilder resultBuilder = new StringBuilder();
someObjectList.stream().map(SomeObject::toString).forEach(resultBuilder::append);
final String result = resultBuilder.toString();
To know more about Streams, you can check this page: http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/, I think it's very helpful.
Although the functional equivalent of what you're trying to achieve here is possible with streams, it's worth reminding you that functional and iterative ways of thinking are not necessarily compatible.
Generally you think of each element on its own, and you don't have visibility over other elements, unless you're using a special function like reduce.
Here's something that does what you've asked for:
final List<Object> objectList = Arrays.asList("a", "b", "c", "d");
String concatString = objectList.stream()
.map(e -> e.toString())
.reduce((result, element) -> result.concat(e))
.get();
Map turns the entire stream into a list, but with the toString function called separately on every element. Reduce is more complex. It can be described as an accumulation. It executes a function between the result, and the current element. In this case, it takes the first element, and concatenates it to the second. It then takes the first/second concatenation, and applies the same function to the third. And so on.
Instead of dealing with lambdas, you can also pass in methods directly, to tighten up your code a bit:
String result = objectList.stream()
.map(Object::toString)
.reduce(String::concat)
.get();
Is it valid to use findFirst() and map() in pipeline.findFirst is shortcircuit method whereas map is intermediate operation.
this.list.stream().filter(t -> t.name.equals("pavan")).findFirst().map(toUpperCase()).orElse(null);
Is it valid to use map in pipeline like above??
Yes, you can use map after findFirst. The Key thing to know here is that findFirst() returns an Optional and hence, you can't simply use the return value without first checking whether the optional has got a value or not. The snippet below assumes that you were working with a list of objects of Person class.
Optional<String> result = this.list.stream()
.filter(t -> t.name.equals("pavan")) // Returns a stream consisting of the elements of this stream that match the given predicate.
.findFirst() // Returns an Optional describing the first element of this stream, or an empty Optional if the stream is empty. If the stream has no encounter order, then any element may be returned.
.map(p -> p.name.toUpperCase()); // If a value is present, apply the provided mapping function to it, and if the result is non-null, return an Optional describing the result. Otherwise return an empty Optional.
// This check is required!
if (result.isPresent()) {
String name = result.get(); // If a value is present in this Optional, returns the value, otherwise throws NoSuchElementException.
System.out.println(name);
} else {
System.out.println("pavan not found!");
}
One more error with your snippet was where you were using toUpperCase. It needs a String, whereas the implicit argument that was getting passed in your snippet was an object of Person class.
How can I check if a Stream is empty and throw an exception if it's not, as a non-terminal operation?
Basically, I'm looking for something equivalent to the code below, but without materializing the stream in-between. In particular, the check should not occur before the stream is actually consumed by a terminal operation.
public Stream<Thing> getFilteredThings() {
Stream<Thing> stream = getThings().stream()
.filter(Thing::isFoo)
.filter(Thing::isBar);
return nonEmptyStream(stream, () -> {
throw new RuntimeException("No foo bar things available")
});
}
private static <T> Stream<T> nonEmptyStream(Stream<T> stream, Supplier<T> defaultValue) {
List<T> list = stream.collect(Collectors.toList());
if (list.isEmpty()) list.add(defaultValue.get());
return list.stream();
}
This may be sufficient in many cases
stream.findAny().isPresent()
The other answers and comments are correct in that to examine the contents of a stream, one must add a terminal operation, thereby "consuming" the stream. However, one can do this and turn the result back into a stream, without buffering up the entire contents of the stream. Here are a couple examples:
static <T> Stream<T> throwIfEmpty(Stream<T> stream) {
Iterator<T> iterator = stream.iterator();
if (iterator.hasNext()) {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
} else {
throw new NoSuchElementException("empty stream");
}
}
static <T> Stream<T> defaultIfEmpty(Stream<T> stream, Supplier<T> supplier) {
Iterator<T> iterator = stream.iterator();
if (iterator.hasNext()) {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
} else {
return Stream.of(supplier.get());
}
}
Basically turn the stream into an Iterator in order to call hasNext() on it, and if true, turn the Iterator back into a Stream. This is inefficient in that all subsequent operations on the stream will go through the Iterator's hasNext() and next() methods, which also implies that the stream is effectively processed sequentially (even if it's later turned parallel). However, this does allow you to test the stream without buffering up all of its elements.
There is probably a way to do this using a Spliterator instead of an Iterator. This potentially allows the returned stream to have the same characteristics as the input stream, including running in parallel.
If you can live with limited parallel capablilities, the following solution will work:
private static <T> Stream<T> nonEmptyStream(
Stream<T> stream, Supplier<RuntimeException> e) {
Spliterator<T> it=stream.spliterator();
return StreamSupport.stream(new Spliterator<T>() {
boolean seen;
public boolean tryAdvance(Consumer<? super T> action) {
boolean r=it.tryAdvance(action);
if(!seen && !r) throw e.get();
seen=true;
return r;
}
public Spliterator<T> trySplit() { return null; }
public long estimateSize() { return it.estimateSize(); }
public int characteristics() { return it.characteristics(); }
}, false);
}
Here is some example code using it:
List<String> l=Arrays.asList("hello", "world");
nonEmptyStream(l.stream(), ()->new RuntimeException("No strings available"))
.forEach(System.out::println);
nonEmptyStream(l.stream().filter(s->s.startsWith("x")),
()->new RuntimeException("No strings available"))
.forEach(System.out::println);
The problem with (efficient) parallel execution is that supporting splitting of the Spliterator requires a thread-safe way to notice whether either of the fragments has seen any value in a thread-safe manner. Then the last of the fragments executing tryAdvance has to realize that it is the last one (and it also couldn’t advance) to throw the appropriate exception. So I didn’t add support for splitting here.
You must perform a terminal operation on the Stream in order for any of the filters to be applied. Therefore you can't know if it will be empty until you consume it.
Best you can do is terminate the Stream with a findAny() terminal operation, which will stop when it finds any element, but if there are none, it will have to iterate over all the input list to find that out.
This would only help you if the input list has many elements, and one of the first few passes the filters, since only a small subset of the list would have to be consumed before you know the Stream is not empty.
Of course you'll still have to create a new Stream in order to produce the output list.
I think should be enough to map a boolean
In code this is:
boolean isEmpty = anyCollection.stream()
.filter(p -> someFilter(p)) // Add my filter
.map(p -> Boolean.TRUE) // For each element after filter, map to a TRUE
.findAny() // Get any TRUE
.orElse(Boolean.FALSE); // If there is no match return false
Following Stuart's idea, this could be done with a Spliterator like this:
static <T> Stream<T> defaultIfEmpty(Stream<T> stream, Stream<T> defaultStream) {
final Spliterator<T> spliterator = stream.spliterator();
final AtomicReference<T> reference = new AtomicReference<>();
if (spliterator.tryAdvance(reference::set)) {
return Stream.concat(Stream.of(reference.get()), StreamSupport.stream(spliterator, stream.isParallel()));
} else {
return defaultStream;
}
}
I think this works with parallel Streams as the stream.spliterator() operation will terminate the stream, and then rebuild it as required
In my use-case I needed a default Stream rather than a default value. that's quite easy to change if this is not what you need
I would simply use:
stream.count()>0
The best simple solution I could find that does not consume the stream or convert to iterators is:
public Stream<Thing> getFilteredThings() {
AtomicBoolean found = new AtomicBoolean(false);
Stream<Thing> stream = getThings().stream()
.filter(Thing::isFoo)
.filter(Thing::isBar)
.forEach(x -> {
found.set(true);
// do useful things
})
;
if (!found.get()) {
throw new RuntimeException("No foo bar things available");
}
}
Feel free to suggest improvements..